Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow subset of operations #38

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ That's the reason for me to look into an automate way to get the job done.
## Benefit of the Math Worksheet Generator
With the Math Worksheet Generator, you can create a PDF with unique questions, as needed, in a fraction of second.

There are five choices:
There are four operations:
1. Addition
2. Subtraction
3. Multiplication
4. Division
5. Mixed

Any subset of these operations can be specified.

## Requirements
[python3](https://www.python.org/downloads/)
Expand All @@ -43,6 +44,10 @@ For addition only worksheet:
```
python3 run.py --type +
```
For multiplication and division only worksheet:
```
python3 run.py --type /x
```
For calculation up to 3 digits range:
```
python3 run.py --digits 3
Expand Down
39 changes: 29 additions & 10 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

class MathWorksheetGenerator:
"""class for generating math worksheet of specified size and main_type"""
def __init__(self, type_: str, max_number: int, question_count: int):
self.main_type = type_
def __init__(self, types: tuple, max_number: int, question_count: int):
self.all_types = types
self.max_number = max_number
self.question_count = question_count
self.pdf = FPDF()
Expand Down Expand Up @@ -53,14 +53,12 @@ def division_helper(self, num) -> [int, int, int]:
def generate_question(self) -> QuestionInfo:
"""Generates each question and calculate the answer depending on the type_ in a list
To keep it simple, number is generated randomly within the range of 0 to 100
:return: list of value1, main_type, value2, and answer for the generated question
:return: list of value1, current_type, value2, and answer for the generated question
"""
num_1 = random.randint(0, self.max_number)
num_2 = random.randint(0, self.max_number)
if self.main_type == 'mix':
current_type = random.choice(['+', '-', 'x', '/'])
else:
current_type = self.main_type

current_type = random.choice(self.all_types)

if current_type == '+':
answer = num_1 + num_2
Expand Down Expand Up @@ -240,21 +238,42 @@ def main(type_, size, question_count, filename):
new_pdf.pdf.output(filename)


def operation_type(string):
"""Operation type callable for parser."""
# allowed operations
ops = ('+', '-', 'x', '/')
# return all operations if mix
if string == 'mix':
return ops
# check all ops are legal
for op in string:
if op not in ops:
msg = f'{op} is not an allowed operation'
raise argparse.ArgumentTypeError(msg)
# check no duplicate ops
if len(set(string)) != len(string):
msg = f'cannot have duplicate types'
raise argparse.ArgumentTypeError(msg)
# return tuple of ops
return tuple(string)


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Generate Maths Addition/Subtraction/Multiplication Exercise Worksheet'
)
parser.add_argument(
'--type',
default='+',
choices=['+', '-', 'x', '/', 'mix'],
help='type of calculation: '
type=operation_type,
help='type(s) of calculation: '
'+: Addition; '
'-: Subtraction; '
'x: Multiplication; '
'/: Division; '
'mix: Mixed; '
'(default: +)',
'(default: +)'
'Types can be combined as a single parameter.',
)
parser.add_argument(
'--digits',
Expand Down
24 changes: 12 additions & 12 deletions tests/test_math_worksheet_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,67 +7,67 @@
class TestStringMethods(unittest.TestCase):

def test_generate_question_addition(self):
g = Mg(type_='+', max_number=9, question_count=10)
g = Mg(types='+', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] + question[2], question[3])

def test_generate_question_subtraction(self):
g = Mg(type_='-', max_number=9, question_count=10)
g = Mg(types='-', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] - question[2], question[3])
# answer should be greater than 0
self.assertGreaterEqual(question[3], 0)

def test_generate_question_multiplication(self):
g = Mg(type_='x', max_number=9, question_count=10)
g = Mg(types='x', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] * question[2], question[3])

def test_generate_question_division(self):
g = Mg(type_='/', max_number=9, question_count=10)
g = Mg(types='/', max_number=9, question_count=10)
question = g.generate_question()
self.assertEqual(question[0] / question[2], question[3])

def test_generate_question_unsupport_type_(self):
g = Mg(type_='p', max_number=9, question_count=10)
g = Mg(types='p', max_number=9, question_count=10)
with self.assertRaisesRegex(RuntimeError, expected_regex=r"Question main_type p not supported"):
g.generate_question()

def test_get_list_of_questions_correct_count(self):
g = Mg(type_='x', max_number=9, question_count=10)
g = Mg(types='x', max_number=9, question_count=10)
question_list = g.get_list_of_questions(g.question_count)
self.assertEqual(len(question_list), g.question_count)

def test_make_question_page_page_count(self):
g = Mg(type_='x', max_number=9, question_count=2)
g = Mg(types='x', max_number=9, question_count=2)
question_info = [[1, '+', 1, 2]] * g.question_count
g.make_question_page(question_info)
total_page = math.ceil(g.question_count / (g.num_x_cell * g.num_y_cell))
self.assertEqual(total_page, g.pdf.page)

def test_factors_two_digits(self):
g = Mg(type_='x', max_number=9, question_count=2)
g = Mg(types='x', max_number=9, question_count=2)
expect_factors = {1, 2, 4, 13, 26, 52}
self.assertEqual(expect_factors, g.factors(52))

def test_factors_three_digits(self):
g = Mg(type_='x', max_number=9, question_count=2)
g = Mg(types='x', max_number=9, question_count=2)
expect_factors = {1, 2, 3, 4, 6, 12, 73, 146, 219, 292, 438, 876}
self.assertEqual(expect_factors, g.factors(876))

def test_division_helper_zero_input(self):
g = Mg(type_='x', max_number=9, question_count=2)
g = Mg(types='x', max_number=9, question_count=2)
division_info = g.division_helper(0)
self.assertNotEqual(0, division_info[0])

def test_division_helper_divisor_not_equal_one_nor_dividend(self):
g = Mg(type_='x', max_number=9, question_count=2)
g = Mg(types='x', max_number=9, question_count=2)
division_info = g.division_helper(876)
self.assertNotEqual(1, division_info[0])
self.assertNotEqual(division_info[2], division_info[0])

def test_division_helper_divisor_answer_type_is_int(self):
g = Mg(type_='x', max_number=9, question_count=2)
g = Mg(types='x', max_number=9, question_count=2)
division_info = g.division_helper(876)
self.assertIs(type(division_info[2]), int)

Expand Down