-- MathQuiz.mesa
-- Edited by Sweet, February 24, 1981 10:34 PM
DIRECTORY
Ascii,
Inline,
PressDefs,
PressUtilities,
Random,
String;
MathQuiz: PROGRAM
IMPORTS Inline, PressDefs, PressUtilities, Random, String =
BEGIN OPEN PressDefs;
pfdBody: PressFileDescriptor;
pfd: POINTER TO PressFileDescriptor = @pfdBody;
Mica: TYPE = CARDINAL;
MBox: TYPE = RECORD [x,y,w,h: Mica];
LineWidth: Mica ← 30;
CharHeight: Mica;
CharWidth: POINTER TO ARRAY CHARACTER OF Mica;
MathCharWidth: ARRAY CHARACTER OF Mica;
TextCharWidth: ARRAY CHARACTER OF Mica;
AnswerCharWidth: ARRAY CHARACTER OF Mica;
MathCharHeight: Mica;
TextCharHeight: Mica;
AnswerCharHeight: Mica;
Minus: CHARACTER = Ascii.ControlX;
answers: BOOLEAN ← FALSE;
Sort: PUBLIC PROCEDURE [
a: DESCRIPTOR FOR ARRAY OF UNSPECIFIED,
Greater: PROC[UNSPECIFIED, UNSPECIFIED] RETURNS [BOOLEAN]] =
BEGIN
n: CARDINAL = LENGTH[a];
i: CARDINAL;
temp: CARDINAL;
SiftUp: PROC [l, u: CARDINAL] =
BEGIN
s: CARDINAL;
key: CARDINAL ← a[l-1];
DO
s ← l*2;
IF s > u THEN EXIT;
IF s < u AND Greater[a[s+1-1], a[s-1]] THEN s ← s+1;
IF Greater[key, a[s-1]] THEN EXIT;
a[l-1] ← a[s-1];
l ← s;
ENDLOOP;
a[l-1] ← key;
END;
FOR i DECREASING IN [2..n/2] DO SiftUp[i, n]; ENDLOOP;
FOR i DECREASING IN [2..n] DO
SiftUp[1, i];
temp ← a[1-1];
a[1-1] ← a[i-1];
a[i-1] ← temp;
ENDLOOP;
END;
iRandom: ARRAY [0..32) OF CARDINAL;
RandomizeI: PROC [iMax: CARDINAL] =
BEGIN
r: ARRAY [0..32) OF CARDINAL;
rGreater: PROC [x, y: CARDINAL] RETURNS [BOOLEAN] =
{RETURN [r[x] > r[y]]};
i: CARDINAL;
FOR i IN [0..iMax) DO
r[i] ← Random.InRange[0, 1000];
iRandom[i] ← i;
ENDLOOP;
Sort[DESCRIPTOR[@iRandom, iMax], rGreater ];
END;
PointsToMicas: PROC [points: CARDINAL] RETURNS [Mica] =
{RETURN [Inline.LongDiv[Inline.LongMult[points, MicasPerInch],72]]};
StringWidth: PROC [s: STRING] RETURNS [l: Mica] =
BEGIN
l ← 0;
FOR i: CARDINAL IN [0..s.length) DO
l ← l + CharWidth[s[i]];
ENDLOOP;
END;
P1: Mica = PointsToMicas[1];
P2: Mica = PointsToMicas[2];
M1: Mica = MicasPerInch;
M12: Mica = MicasPerInch/2;
M14: Mica = MicasPerInch/4;
M34: Mica = (3*MicasPerInch)/4;
M38: Mica = (3*MicasPerInch)/8;
CenterNum: PROC [n: CARDINAL, box: POINTER TO MBox] =
BEGIN
w: Mica;
ns: STRING ← [2];
String.AppendDecimal[ns, n];
w ← StringWidth[ns];
PutText[pfd, ns, box.x + (box.w-w)/2, box.y + (box.h-CharHeight)/2];
END;
CenterChar: PROC [c: CHARACTER, box: POINTER TO MBox] =
BEGIN
w: Mica;
ns: STRING ← [2];
ns.length ← 1; ns[0] ← c;
w ← StringWidth[ns];
PutText[pfd, ns, box.x + (box.w-w)/2, box.y + (box.h-CharHeight)/2];
END;
HorizNumberSentence: PROC [x,y: Mica, a, b: CARDINAL] RETURNS [Mica] =
BEGIN
box: MBox;
op: CHARACTER ← '+;
TextFont[];
box ← [x: x, y: y-M38, w: M38, h: M38];
CenterNum[a, @box];
box.x ← box.x + M38; box.w ← M14;
CenterChar[op, @box];
box.x ← box.x + M14; box.w ← M38;
CenterNum[b, @box];
box.x ← box.x + M38; box.w ← M14;
CenterChar['=, @box];
PutRectangle[p: pfd,
xstart: box.x + M14,
ystart: y-M38,
xlen: M12,
ylen: P1];
IF answers THEN
BEGIN
c: CARDINAL ← IF op = '+ THEN a+b ELSE a-b;
AnswerFont[];
box.x ← box.x + M14; box.w ← M12;
CenterNum[c, @box];
TextFont[];
END;
RETURN[y - M12];
END;
margin: Mica = (3*M1 + M14)/4;
pwidth: Mica = M1+M34;
DoNumber: PROC [n: CARDINAL, y: Mica] RETURNS [nextY: Mica] =
BEGIN
count: CARDINAL ← 0;
x: Mica ← margin;
RandomizeI[11-n];
FOR i: CARDINAL IN [0..11-n) DO
IF count = 3 THEN {count ← 0; x ← margin; y ← nextY};
nextY ← HorizNumberSentence[x, y, n, iRandom[i]];
x ← x + pwidth + margin;
count ← count + 1;
ENDLOOP;
END;
DoPage: PROC [first, last: CARDINAL] =
BEGIN
y: Mica ← 10*M1;
FOR i: CARDINAL IN [first..last) DO
y ← DoNumber[i, y];
y ← y - M12;
PutRectangle[p: pfd,
xstart: margin,
ystart: y,
xlen: 8*M1+M12-2*margin,
ylen: P1];
y ← y - M12;
ENDLOOP;
y ← DoNumber[last, y];
WritePage[pfd];
END;
TextFont: PROC =
BEGIN
SetFont[p: pfd, Name: "Helvetica", PointSize: 18, Face: 2];
CharHeight ← TextCharHeight;
CharWidth ← @TextCharWidth;
END;
AnswerFont: PROC =
BEGIN
SetFont[p: pfd, Name: "Helvetica", PointSize: 14, Face: 1];
CharHeight ← AnswerCharHeight;
CharWidth ← @AnswerCharWidth;
END;
MathFont: PROC =
BEGIN
SetFont[p: pfd, Name: "Math", PointSize: 10, Face: 0];
CharHeight ← MathCharHeight;
CharWidth ← @MathCharWidth;
END;
DigestFonts: PROC =
BEGIN
[] ← PressUtilities.FindFontWidths[
family: "Helvetica"L,
points: 18,
weight: bold,
slope: regular,
widths: LOOPHOLE[@TextCharWidth]];
TextCharHeight ← PointsToMicas[18];
[] ← PressUtilities.FindFontWidths[
family: "Helvetica"L,
points: 14,
weight: medium,
slope: italic,
widths: LOOPHOLE[@AnswerCharWidth]];
AnswerCharHeight ← PointsToMicas[14];
[] ← PressUtilities.FindFontWidths[
family: "Math"L,
points: 10,
weight: medium,
slope: regular,
widths: LOOPHOLE[@MathCharWidth]];
MathCharHeight ← PointsToMicas[10];
END;
DoQuiz: PROC =
BEGIN
DoPage[0,2];
DoPage[3,6];
DoPage[7,10];
END;
Driver: PROC =
BEGIN
state: Random.State;
DigestFonts[];
InitPressFileDescriptor[pfd, "Math.drill"L];
answers ← FALSE;
Random.ReadState[@state];
DoQuiz[];
ClosePressFile[pfd];
Random.WriteState[@state];
InitPressFileDescriptor[pfd, "Math.key"L];
answers ← TRUE;
DoQuiz[];
ClosePressFile[pfd];
END;
Driver[];
END.