-- MathBox.mesa -- Edited by Sweet, 15-May-81 16:52:37 DIRECTORY Ascii, Inline, IODefs, PressDefs, PressUtilities, Random, String; MathBox: PROGRAM IMPORTS Inline, IODefs, 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; TextCharWidth: ARRAY CHARACTER OF Mica; AnswerCharWidth: ARRAY CHARACTER OF Mica; TextCharHeight: Mica; AnswerCharHeight: Mica; Minus: CHARACTER = Ascii.ControlX; squareDim: Mica = M12; answers: BOOLEAN _ FALSE; Prob: TYPE = RECORD [op: CHARACTER, a,b, c, d: [0..16)]; NullProb: Prob = [0C, 0, 0, 0, 0]; HistSize: CARDINAL = 6; history: ARRAY [0..HistSize) OF Prob _ ALL[NullProb]; hp: CARDINAL _ 0; p1: CARDINAL _ 2; p2: CARDINAL _ 3; Problem: PROC RETURNS [op: CHARACTER, a,b, c, d: CARDINAL] = BEGIN trial: Prob; DO trial _ TrialProblem[]; FOR i: CARDINAL IN [0..HistSize) DO IF history[i] = trial THEN EXIT; REPEAT FINISHED => GO TO ok; ENDLOOP; REPEAT ok => NULL; ENDLOOP; history[hp] _ trial; hp _ (hp+1) MOD HistSize; RETURN [trial.op, trial.a, trial.b, trial.c, trial.d]; END; TrialProblem: PROC RETURNS [trial: Prob] = BEGIN IF Random.InRange[1, p2] <= p1 THEN RETURN[PlusTrialProblem[]] ELSE RETURN[MinusTrialProblem[]]; END; PlusTrialProblem: PROC RETURNS [trial: Prob] = BEGIN total, sum2: CARDINAL; total _ Random.InRange[4, max]; sum2 _ Random.InRange[2, total-2]; trial.op _ '+; [trial.a, trial.b] _ SubProblem[total-sum2]; [trial.c, trial.d] _ SubProblem[sum2]; END; MinusTrialProblem: PROC RETURNS [trial: Prob] = BEGIN a, b, c, d: INTEGER; a _ Random.InRange[4,max]; b _ IF Random.InRange[0, 2*max] = 0 THEN 0 ELSE Random.InRange[1, a-1]; c _ IF Random.InRange[0, 2*max] = 0 THEN 0 ELSE Random.InRange[1, a-1]; d _ Random.InRange[MAX[0, b+c-a], MIN[b, c]]; RETURN[[Minus, a, b, c, d]]; END; w2: CARDINAL _ 3; w3: CARDINAL _ 2; SubProblem: PROC [total: CARDINAL] RETURNS [a, b: CARDINAL] = BEGIN a _ IF total = 0 OR Random.InRange[1, w2*total] <= w3 THEN 0 ELSE Random.InRange[1, total-1]; b _ total - a; IF Random.InRange[1,2] = 1 THEN {t: CARDINAL = a; a _ b; b _ t}; 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; DrawBorder: PROC [box: POINTER TO MBox, lw: Mica] = BEGIN PutRectangle[p: pfd, xstart: box.x, ystart: box.y, xlen: box.w + lw, ylen: lw]; PutRectangle[p: pfd, xstart: box.x, ystart: box.y, xlen: lw, ylen: box.h]; PutRectangle[p: pfd, xstart: box.x + box.w, ystart: box.y, xlen: lw, ylen: box.h]; PutRectangle[p: pfd, xstart: box.x, ystart: box.y + box.h, xlen: box.w + lw, ylen: lw]; END; 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 + P2]; 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 + P2]; END; DoMatrix: PROC [x,y: Mica] = BEGIN box: MBox; op: STRING _ [1]; a, b, c, d: CARDINAL; op.length _ 1; [op[0], a, b, c, d] _ Problem[]; TextFont[]; PutText[pfd, op, x-CharWidth['+], y]; box _ [x: x, y: y-squareDim, w: squareDim, h: squareDim]; DrawBorder[@box, LineWidth]; CenterNum[a, @box]; box.x _ box.x + squareDim; DrawBorder[@box, LineWidth]; CenterNum[b, @box]; box.x _ box.x + squareDim; DrawBorder[@box, LineWidth]; IF answers THEN BEGIN AnswerFont[]; CenterNum[(IF op[0] = '+ THEN a+b ELSE a-b), @box]; TextFont[]; END; box.x _ x; box.y _ box.y - squareDim; DrawBorder[@box, LineWidth]; CenterNum[c, @box]; box.x _ box.x + squareDim; DrawBorder[@box, LineWidth]; CenterNum[d, @box]; box.x _ box.x + squareDim; DrawBorder[@box, LineWidth]; IF answers THEN BEGIN AnswerFont[]; CenterNum[(IF op[0] = '+ THEN c+d ELSE c-d), @box]; TextFont[]; END; box.x _ x; box.y _ box.y - squareDim; DrawBorder[@box, LineWidth]; IF answers THEN BEGIN AnswerFont[]; CenterNum[(IF op[0] = '+ THEN a+c ELSE a-c), @box]; TextFont[]; END; box.x _ box.x + squareDim; DrawBorder[@box, LineWidth]; IF answers THEN BEGIN AnswerFont[]; CenterNum[(IF op[0] = '+ THEN b+d ELSE b-d), @box]; TextFont[]; END; box.x _ box.x + squareDim; DrawBorder[@box, 2*LineWidth]; IF answers THEN BEGIN AnswerFont[]; CenterNum[(IF op[0] = '+ THEN a+b+c+d ELSE a-b-c+d), @box]; TextFont[]; END; END; squaresAcross: CARDINAL = 3; squaresDown: CARDINAL = 4; DoPage: PROC = BEGIN x, y: Mica; boxDim: Mica = 3*squareDim; extraX: Mica = (6*M1+M12 - squaresAcross*boxDim)/(squaresAcross-1); extraY: Mica = (9*M1 - squaresDown*boxDim)/(squaresDown-1); y _ 10*M1; THROUGH [0..squaresDown) DO x _ M1; THROUGH [0..squaresAcross) DO DoMatrix[x, y]; x _ x + boxDim + extraX; ENDLOOP; y _ y - boxDim - extraY; ENDLOOP; 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; 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]; END; max: INTEGER _ 12; pages: CARDINAL _ 3; Driver: PROC = BEGIN state: Random.State; BEGIN OPEN IODefs; WriteString["max: "L]; max _ ReadNumber[max, 10]; WriteChar[CR]; WriteString["Pages: "L]; pages _ ReadNumber[pages, 10]; WriteChar[CR]; END; DigestFonts[]; InitPressFileDescriptor[pfd, "Math.drill"L]; answers _ FALSE; Random.ReadState[@state]; THROUGH [0..pages) DO DoPage[]; ENDLOOP; ClosePressFile[pfd]; Random.WriteState[@state]; history _ ALL[NullProb]; InitPressFileDescriptor[pfd, "Math.key"L]; answers _ TRUE; THROUGH [0..pages) DO DoPage[]; ENDLOOP; ClosePressFile[pfd]; END; Driver[]; END.