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