M Web Magazine 006 (March 5, 1998 - June 4, 1998)

M Tutorial (part 2/6)

 

$PIECE continued

Up to now we have looked at how to use $PIECE to extract data from within a string we'll consider how it can also be used to fit data with compartments of a string. The program below compliments INTFN103 by allowing our tutor to fill in the data about his five students.

INTFN105Þ;Program demonstrates intrinsic functions - Chris Bonnici - Aug 1997
Þ;M Web Magazine @ http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞN STUDMRK,STUD,EXAM,BUF,MARK
ÞS STUDMRK=""
10ÞW /ED(2),/CUP(1,1),"Mark Update Program"
ÞR /CUP(5,1),"Enter Student # (1 - 5 or <Enter>): ",STUD
ÞQ:STUD=""
ÞG:STUD<1!(STUD>5) 10
20ÞR /CUP(7,1),/EL(2),"Which Exam (1 - 3 or <Enter>): ",EXAM
ÞG:EXAM="" 10
ÞG:EXAM<1!(EXAM>3) 20
30ÞR /CUP(9,1),/EL(2),"Enter Mark (0 - 100 or <Enter>): ",MARK
ÞG:MARK="" 20
ÞG:MARK<0!(MARK>100) 30
ÞS BUF=$P(STUDMRK,"~",STUD),$P(BUF,"#",EXAM)=MARK,$P(STUDMRK,"~",STUD)=BUF
ÞW /CUP(20,1),STUDMRK,/CUP(9,1),/EL(2)
ÞG 20

The code is quite easy to follow although one (coloured) line merits a bit of discussion. This line updates the variable STUDMRK. First we extract the student into the variable BUF, after which we fill in the mark. Our final step is to update the variable.

There is no need to fill in the data in any particular order. The delimiter characters are added as needed to as to maintain the correct positioning. Below is a dry run analysis of the variable STUDMRK. It will help you understand how this program is working by counting the different delimiters.

STUD EXAM MARK S BUF=$P(STUDMRK,"~",STUD)
S $P(BUF,"#",EXAM)=MARK
S $P(STUDMRK,"~",STUD)=BUF
4 3 55 ~~~##55
2 1 43 ~43~~##55
5 1 88 ~43~~##55~88
5 2 78 ~43~~##55~88#78
4 1 60 ~43~~60##55~88#78
1 1 99 99~43~~60##55~88#78

Before we move in to the next function, there are a few thing you should be aware of:

  • The amount you can store within a variable is limited by how many characters the variable can store. You must check you implementation on this limit.
  • The delimiter must be exclusively used to delimit partitions. Using it as part the data will introduce fictitious partitions that will offset all readings. (Look at INTFN106).

INTFN106Þ;Program demonstrates intrinsic functions - Chris Bonnici - Aug 1997
Þ;M Web Magazine @ http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞN NAMES
ÞS NAMES=""
ÞF D Q:NME=""
Þ.R !,"Enter a Name: ",NME
Þ.Q:NME=""
Þ.S NAMES=NME_"A"_NAMES
Þ.Q
ÞF I=1:1 S NME=$P(NAMES,"A",I) Q:NME="" W !,NME
ÞQ

Try running INTFN106 (entering a few names that have A within them). While some may think this rather obvious, it is very important that the delimiter character be chosen so that it guarantees that data and delimiters are distinct. Can you guarantee that someone will not hit a # or a ~?

INTFN107Þ;Program demonstrates intrinsic functions - Chris Bonnici - Aug 1997
Þ;M Web Magazine @ http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞN NAMES,NME
ÞS NAMES=""
ÞF D Q:NME=""
Þ.R !,"Enter a Name: ",NME
Þ.Q:NME=""
Þ.S NAMES=NME_"~#~"_NAMES
Þ.Q
ÞF I=1:1 S NME=$P(NAMES,"~#~",I) Q:NME="" W !,NME
ÞQ

INTFN107 plays safe by making the delimiter a unique combination of characters. This comes at a cost; it increases the size of the string. An alternative method is to ensure that each value read from the user does not contain the delimiter string. Write a version of this validation read command (ideally as a library routine or function).

We did not mention the <last> parameter of the $P command. If specified this will act on the string between <first> and <last>.

INTFN108Þ;Program demonstrates intrinsic functions - Chris Bonnici - Aug 1997
Þ;M Web Magazine @ http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞN STR
ÞS STR="1%2%3%4%5"
ÞW !,STR
ÞS $P(STR,"%",2,4)="<--->"
ÞW !,STR
ÞQ

1%2%3%4%5
1%<--->%5

 

$RANDOM(<integer>) or $R (<integer>)

This function will return a number in the range 0 >= $R(x) < x (the number will lie in the range between 0 and x-1). It is important to appreciate that computers do not generate true random numbers, this number is generated via a mathematical algorithm that many-a-times makes use of the computer’s internal clock. Although this means that you can’t probably use a normal PC to run a lottery, under many scenarios this type of randomness is more than sufficient.

INTFN109Þ;Program demonstrates intrinsic functions - Chris Bonnici - Aug 1997
Þ;M Web Magazine @ http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞN HOWMANY,I,PIECE,TOTAL
ÞS HOWMANY="",TOTAL=0
ÞF I=1:1:9000 D
Þ.S PIECE=$RANDOM(100)+1
Þ.S $P(HOWMANY,"~",PIECE)=$P(HOWMANY,"~",PIECE)+1
Þ.Q
ÞF I=1:1:100 W $J(I-1_"->"_$P(HOWMANY,"~",I),10) S TOTAL=TOTAL+$P(HOWMANY,"~",I)
ÞW !!,"Total :",TOTAL
ÞQ

The program above loops for 9000 times. In each iteration, it "selects" a number between 0 and 99--$R(100). We keep a tally of the frequency each number is pulled out of the hat in a string variable using the $P to select the compartment. Since trying to store in the zero partition is not possible (even though you don’t get an error) we offset the array by one. Once this loop is over we print the selection frequency of each number.

If you are new to programming, a question that might crop to mind is the purpose of introducing a chaos function into programming. While it is correct to say that on many occasions we want to run the same sequence of events in the same faithful manner over and over and over again, there are situations (games and simulations) when we want to introduce variation between one program run and another.

Imagine a football manager game. What would happen if every time the user runs the game s/he faces the same fates and fortunes? $RANDOM can change them from one simulation to another.

INTFN110Þ;Program demonstrates intrinsic functions - Chris Bonnici - Aug 1997
Þ;M Web Magazine @ http://geocities.datacellar.net/SiliconValley/7041/mwm.html
Þ;You are using this program at your own risk
Þ;
ÞN I,DECK,PLAY1,PLAY2,CARD,VALID
ÞS (DECK,PLAY1,PLAY2)=""
ÞF I=1:1:52 S $P(DECK,"~",I)=$$CARDFACE(I)
ÞD INIT(.DECK,.PLAY1)
ÞD INIT(.DECK,.PLAY2)
ÞW #
ÞD LAYCARDS(PLAY1,1)
ÞD LAYCARDS(PLAY2,20)
10ÞR /CUP(23,1),/EL(2),"1: Choose Card> ",CARD
ÞS VALID=0
ÞF I=1:1:26 I $P(PLAY1,"~",I)=CARD D Q
Þ.S $P(PLAY1,"~",I)="",VALID=1
Þ.W /CUP(10,30),CARD
Þ.D LAYCARDS(PLAY1,1)
Þ.W /CUP(24,1),/EL(2),$$PLAYCARD(CARD)
Þ.Q
ÞG:'VALID 10
20ÞR /CUP(23,1),/EL(2),"2: Choose Card> ",CARD
ÞS VALID=0
ÞF I=1:1:26 I $P(PLAY2,"~",I)=CARD D Q
Þ.S $P(PLAY2,"~",I)="",VALID=1
Þ.W /CUP(10,30),CARD
Þ.D LAYCARDS(PLAY2,20)
Þ.W /CUP(24,1),/EL(2),$$PLAYCARD(CARD)
Þ.Q
ÞG:'VALID 20
ÞG 10
Þ;*** EOR ***
Þ; Player's cards are placed on table
LAYCARDS(PLAYER,ROW)ÞN I,COL
ÞW /CUP(ROW,1),/EL(2),/CUP(ROW+1,1),/EL(2)
ÞS COL=1
ÞF I=1:1:26 I $P(PLAYER,"~",I)'="" W /CUP(ROW,(COL-1)*5+1),$P(PLAYER,"~",I) S COL=COL+1 I COL>13 S ROW=ROW+1,COL=1
ÞQ
Þ;*** EOR ***
Þ; Game Initialisation
INIT(DECK,PLAYER)ÞN I,CARD
ÞS I=1
ÞF S CARD=$R(52)+1 I $P(DECK,"~",CARD)'="" D Q:I>26
Þ.S $P(PLAYER,"~",I)=$P(DECK,"~",CARD) ; Pass card to player
Þ.S $P(DECK,"~",CARD)="" ; Remove card from deck
Þ.S I=I+1
Þ.Q
ÞQ
Þ;*** EOR ***
Þ; The Card number is converted to the appropriate type and played. 1 - 13 Hearts, 14 - 26 Spades, 27 - 39 Clubs, 40 - 52 Diamonds
CARDFACE(CARDNUM)ÞN FACE
ÞS FACE=CARDNUM#13
ÞS:FACE=0 FACE="K"
ÞS:FACE=12 FACE="Q"
ÞS:FACE=11 FACE="J"
ÞI CARDNUM<14 S FACE=FACE_"H"
ÞE I CARDNUM<27 S FACE=FACE_"S"
ÞE I CARDNUM<40 S FACE=FACE_"C"
ÞE S FACE=FACE_"D"
ÞQ FACE
Þ;*** EOR ***
Þ; Convert a card face to its numeric equivalent
PLAYCARD(CARD)ÞN FACE,NUM
Þ; Convert Face to Card Number
ÞS NUM=$E(CARD,1,$L(CARD)-1),FACE=$E(CARD,$L(CARD))
ÞS:NUM="K" NUM=13
ÞS:NUM="Q" NUM=12
ÞS:NUM="J" NUM=11
ÞS:FACE="H" FACE=0
ÞS:FACE="S" FACE=12
ÞS:FACE="C" FACE=25
ÞS:FACE="D" FACE=39
ÞS NUM=NUM+FACE
ÞQ NUM

The program above is a little game of cards. In it the cards are split evenly between two players. The $RANDOM function is used to handle out different cards to the two players on different runs of the game.

Of particular interest in this game is how a random number between 1 and 52 is converted into the value and face of the card and how it is ensured that no card is dealt twice. The routine PLAYCARD converts a face card to its equivalent number. Although this routine in not really necessary as far as the program is concerned, we have included it here so that you can analyse how the card is converted back to a number.

We did not include any game play in this program and the challenge we pose is that of turning this program into a fully fledged game. The code modularity should make it simple to alter the dealing properties of your game and the add appropriate gaming into it. (If you care to share your finished program with us, we would be mighty glad).

Continued...

E&OE

1