Last active
August 29, 2015 13:55
-
-
Save bdkosher/8734388 to your computer and use it in GitHub Desktop.
Generates addition and subtraction math problems.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import groovy.transform.* | |
/* | |
* Configuration: | |
* | |
* @twoDigit - if false, problems will be single digit operands and answers; if true, one or two digits | |
* @independentProblems - if false, the answer to the previous problem is the first operand of the | |
* subsequent problem, and a finalResult value must be specified | |
* @additionOnly - if true, all problems generated will be addition; if false, it'll be a mix of | |
* addition and subtraction | |
* | |
*/ | |
@Field int nbrOfDigits = 3 | |
@Field boolean independentProblems = true | |
@Field boolean additionOnly = false | |
Number finalResult = independentProblems ? pickAnyNumber() : 7 // this number is the final answer | |
if (finalResult > Math.pow(10, nbrOfDigits)) { | |
finalResult = finalResult % Math.pow(10, nbrOfDigits - 1) | |
} | |
Number nbrOfProblems = independentProblems ? 24 : 32 // based on how many fill up a page when printed via Chrome | |
class Problem { | |
String problem, operator | |
Number firstOperand, secondOperand, answer | |
Problem(String str) { | |
def (op1, op, op2, eq, ans) = str.split(' ') | |
this.problem = str | |
this.firstOperand = op1 as Integer | |
this.operator = op | |
this.secondOperand = op2 as Integer | |
this.answer = ans as Integer | |
} | |
@Override | |
String toString() { problem } | |
} | |
/** | |
* Generates a random two-digit number | |
*/ | |
Number pickAnyNumber() { | |
new Random().nextInt(('9' * nbrOfDigits) as int) + 1 | |
} | |
/** | |
* Makes a math problem (addition or subtraction) where the answer is the given $answer. | |
* An optional first operand may be provided, as well. | |
* @return the problem as a String | |
*/ | |
Problem makeMathProblem(Number answer, Number firstNumber = pickAnyNumber()) { | |
def secondNumber = answer - firstNumber | |
if (secondNumber < 0) { | |
if (additionOnly) { | |
makeMathProblem(answer, Math.abs(secondNumber)) // use the second number | |
} else { | |
new Problem("$firstNumber - ${Math.abs(secondNumber)} = $answer") | |
} | |
} else { | |
new Problem("$firstNumber + $secondNumber = $answer") | |
} | |
} | |
/* | |
* Makes $howManyProblems math problems where the answer of the previous problem | |
* is used as a operand to the subsequent problem. The final answer is the given | |
* $answer. | |
* @return a list of math problems | |
*/ | |
List<Problem> makeMathProblems(Number answer, Number howManyProblems) { | |
def problems = [] | |
Number intermediateAnswer = pickAnyNumber() | |
if (howManyProblems > 1) { | |
(1..(howManyProblems - 1)).each { | |
Number firstNumber = intermediateAnswer | |
intermediateAnswer = pickAnyNumber() | |
problems << makeMathProblem(intermediateAnswer, independentProblems ? pickAnyNumber() : firstNumber) | |
} | |
} | |
problems << makeMathProblem(answer, independentProblems ? pickAnyNumber() : intermediateAnswer) | |
problems | |
} | |
// generate 32 problems as printable HTML (four columns of 8 problems) | |
def allProblems = makeMathProblems(finalResult, nbrOfProblems) | |
def out = new File(/C:\Users\Joe\Desktop\Joe\mosesmath.html/) | |
out.bytes = [] as byte[] | |
out << """ | |
<html> | |
<head> | |
<!-- targetting Chrome --> | |
<style type="text/css"> | |
body { | |
margin: 35px 35px 0px; | |
} | |
.problem-series { | |
float: left; | |
width: 66px; | |
margin: 0px 40px; | |
} | |
.problem { | |
letter-spacing: ${nbrOfDigits < 3 ? '5px' : '3px'}; | |
font-size: ${nbrOfDigits < 3 ? '28pt' : '22pt'}; | |
margin: 0px; | |
text-align: right; | |
padding-bottom: ${nbrOfDigits < 3 ? '0px' : '20px'}; | |
} | |
.operator, .second-op { | |
display: inline; | |
text-align: right; | |
} | |
.operator { | |
width: 10px; | |
max-width: 10px; | |
font-weight: bold; | |
float: left; | |
margin-left: -4px; | |
} | |
.first-op, .answer { | |
padding-left: 17px; | |
} | |
.second-op { | |
padding-left: 6px; | |
margin-right: ${ nbrOfDigits < 3 ? 0 : -3 }px; | |
} | |
.answer { | |
border-top: solid 2px black; | |
width: 80%; | |
height: 30px; | |
padding-top: 12px; /* make some room for carrying 1s and whatnot */ | |
} | |
</style> | |
</head> | |
<body> | |
""" | |
def problemSeries = allProblems.collate((allProblems.size() / 4) as int, true) | |
boolean first = true | |
problemSeries.each { problems -> | |
out << '<div class="problem-series">\n' | |
boolean firstInSeries = true | |
problems.each { problem -> | |
out << '<div class="problem">\n' | |
if (firstInSeries) { | |
if (first) { | |
out << "<div class=\"first-op\">$problem.firstOperand</div>\n" | |
} else { | |
out << '<div class="first-op">__</div>\n' | |
} | |
if (!independentProblems) { | |
first = false | |
firstInSeries = false | |
} | |
} | |
def opChar = problem.operator == '-' ? '–' : problem.operator | |
out << "<div class=\"operator\">$opChar</div>\n" | |
out << "<div class=\"second-op\">$problem.secondOperand</div>\n" | |
out << "<div class=\"answer\"></div>\n" | |
out << '</div>\n' | |
} | |
out << '</div>\n' | |
} | |
out << """ | |
</body> | |
</html> | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment