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