Skip to content

Instantly share code, notes, and snippets.

@bdkosher
Last active August 29, 2015 13:55
Show Gist options
  • Save bdkosher/8734388 to your computer and use it in GitHub Desktop.
Save bdkosher/8734388 to your computer and use it in GitHub Desktop.
Generates addition and subtraction math problems.
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 == '-' ? '&ndash;' : 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