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