-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e08097e
commit 4c0a12b
Showing
4 changed files
with
206 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Maths Worksheet Generator | ||
|
||
 | ||
|
||
## Background | ||
One of my best friends is training his 5 years old with basic addition questions from store-bought material. Good for one time usage as kid is smart enough to memorize the answers. He wants to give him more practice. | ||
|
||
Two solutions: | ||
1. keep buying more one time usage materials (less beer budget); or | ||
2. make question sets with the number pairs and calculate the answer for each question manually (less beer time) | ||
|
||
Not ideal. | ||
|
||
That's the reason for me to look into an automate way to get the job done. | ||
|
||
## Benefit of the Maths Worksheet Generator | ||
You can generate as many non duplicated questions as you need with the answer sheet in a fraction of second. | ||
|
||
There are four choices: | ||
1. Addition | ||
2. Subtraction | ||
3. Multiplication | ||
4. Mixed | ||
|
||
## Requirements | ||
1. [python3](https://www.python.org/downloads/) | ||
2. [fpdf](https://pypi.org/project/fpdf/) | ||
|
||
## How to Use | ||
1. Generate the worksheet in pdf format with the following command: | ||
``` | ||
python3 run.py --type [+|-|x|mix] | ||
``` | ||
For example, for addition only worksheet, use the following command: | ||
``` | ||
python3 run.py --type + | ||
``` | ||
3. Print out the generated file `worksheet.pdf` | ||
|
||
## Sample | ||
[sample worksheet](sample-worksheet.pdf) | ||
|
||
## Code Overview | ||
Everything is written in python in `run.py`. You can play with the font and gird size with the variables under the `# Basic settings` section. | ||
|
||
## Contributing | ||
Any suggestion will be appreciated. You can simply create a pull request with your idea. Feel free to fork the project too. | ||
|
||
## Special Thanks | ||
My long time friend San for the inspiration of this project and lovely sons Tim and Hin. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
import argparse | ||
import random | ||
from fpdf import FPDF | ||
|
||
|
||
class maths_worksheet_generator(): | ||
pdf = FPDF() | ||
# Basic settings | ||
small_font_size = 10 | ||
middle_font_size = 15 | ||
large_font_size = 30 | ||
size = 21 | ||
tiny_pad_size = 2 | ||
pad_size = 10 | ||
large_pad_size = 30 | ||
num_x_cell = 4 | ||
num_y_cell = 2 | ||
total_question = 80 # Must be a multiple of 40 | ||
font_1 = 'Times' | ||
font_2 = 'Arial' | ||
|
||
def generate_question(self, type): | ||
# Generate 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 | ||
num_1 = random.randint(0, 100) | ||
num_2 = random.randint(0, 100) | ||
if type == 'mix': | ||
type = random.choice(['+', '-', 'x']) | ||
if type == '+': | ||
answer = num_1 + num_2 | ||
elif type == '-': | ||
answer = num_1 - num_2 | ||
elif type == 'x': | ||
answer = num_1 * num_2 | ||
else: | ||
raise RuntimeError('Question type {} not supported'.format(type)) | ||
return [num_1, type, num_2, answer] | ||
|
||
def get_list_of_questions(self, type): | ||
# Generate all the questions for the worksheet in a list | ||
questions = [] | ||
while len(questions) < self.total_question: | ||
new_question = self.generate_question(type) | ||
if new_question not in questions: | ||
questions.append(new_question) | ||
return questions | ||
|
||
def make_question_page(self, data): | ||
# Prepare a single page of question | ||
total_page = int(self.total_question / (self.num_x_cell * self.num_y_cell)) | ||
for page in range(0, total_page): | ||
self.pdf.add_page(orientation='L') | ||
self.print_question_row(data, (page) * (2 * self.num_x_cell)) | ||
self.print_horizontal_seperator() | ||
self.print_question_row(data, (page) * (2 * self.num_x_cell) + self.num_x_cell) | ||
|
||
def print_top_row(self, question_num): | ||
# Helper function to print first row of a question | ||
self.pdf.set_font(self.font_1, size=self.middle_font_size) | ||
self.pdf.cell(self.pad_size, self.pad_size, txt=question_num, border='LT', ln=0, align='C') | ||
self.pdf.cell(self.size, self.pad_size, border='T', ln=0, align='C') | ||
self.pdf.cell(self.size, self.pad_size, border='T', ln=0, align='C') | ||
self.pdf.cell(self.pad_size, self.pad_size, border='TR', ln=0, align='C') | ||
|
||
def print_second_row(self, num): | ||
# Helper function to print second row of a question | ||
self.pdf.set_font(self.font_2, size=self.large_font_size) | ||
self.pdf.cell(self.pad_size, self.size, border='L', ln=0, align='C') | ||
self.pdf.cell(self.size, self.size, border=0, ln=0, align='C') | ||
self.pdf.cell(self.size, self.size, txt=str(num), border=0, ln=0, align='R') | ||
self.pdf.cell(self.pad_size, self.size, border='R', ln=0, align='C') | ||
|
||
def print_third_row(self, num, type): | ||
# Helper function to print third row of a question | ||
self.pdf.set_font(self.font_2, size=self.large_font_size) | ||
self.pdf.cell(self.pad_size, self.size, border='L', ln=0, align='C') | ||
self.pdf.cell(self.size, self.size, txt=type, border=0, ln=0, align='L') | ||
self.pdf.cell(self.size, self.size, txt=str(num), border=0, ln=0, align='R') | ||
self.pdf.cell(self.pad_size, self.size, border='R', ln=0, align='C') | ||
|
||
def print_bottom_row(self): | ||
# Helper function to print bottom row of question | ||
self.pdf.set_font(self.font_2, size=self.large_font_size) | ||
self.pdf.cell(self.pad_size, self.size, border='LB', ln=0, align='C') | ||
self.pdf.cell(self.size, self.size, border='TB', ln=0, align='C') | ||
self.pdf.cell(self.size, self.size, border='TB', ln=0, align='R') | ||
self.pdf.cell(self.pad_size, self.size, border='BR', ln=0, align='C') | ||
|
||
def print_edge_vertical_seperator(self): | ||
# Print space between question for the top or bottom row | ||
self.pdf.cell(self.pad_size, self.pad_size, border=0, ln=0) | ||
|
||
def print_middle_vertical_seperator(self): | ||
# Print space betwen question for the second or third row | ||
self.pdf.cell(self.pad_size, self.size, border=0, ln=0) | ||
|
||
def print_horizontal_seperator(self): | ||
# Print line breaker between two rows of questions | ||
self.pdf.cell(self.size, self.size, border=0, ln=0, align='C') | ||
self.pdf.ln() | ||
|
||
def print_question_row(self, data, offset): | ||
# Print a single row of questions (total question in a row is set by num_x_cell) | ||
for x in range(0, self.num_x_cell): | ||
self.print_top_row(str(x + 1 + offset)) | ||
self.print_edge_vertical_seperator() | ||
self.pdf.ln() | ||
for x in range(0, self.num_x_cell): | ||
self.print_second_row(data[x + offset][0]) | ||
self.print_middle_vertical_seperator() | ||
self.pdf.ln() | ||
for x in range(0, self.num_x_cell): | ||
self.print_third_row(data[x + offset][2], data[x + offset][1]) | ||
self.print_middle_vertical_seperator() | ||
self.pdf.ln() | ||
for _ in range(0, self.num_x_cell): | ||
self.print_bottom_row() | ||
self.print_edge_vertical_seperator() | ||
self.pdf.ln() | ||
|
||
def make_answer_page(self, data): | ||
# Print answer sheet | ||
self.pdf.add_page(orientation='L') | ||
self.pdf.set_font(self.font_1, size=self.large_font_size) | ||
self.pdf.cell(self.large_pad_size, self.large_pad_size, txt='Answers', border=0, ln=1, align='C') | ||
|
||
for i in range(len(data)): | ||
self.pdf.set_font(self.font_1, size=self.small_font_size) | ||
self.pdf.cell(self.pad_size, self.pad_size, txt='{}:'.format(i+1), border='TLB', ln=0, align='R') | ||
self.pdf.set_font(self.font_2, size=self.small_font_size) | ||
self.pdf.cell(self.pad_size, self.pad_size, txt=str(data[i][3]), border='TB', ln=0, align='R') | ||
self.pdf.cell(self.tiny_pad_size, self.pad_size, border='TRB', ln=0, align='R') | ||
self.pdf.cell(self.tiny_pad_size, self.pad_size, border=0, ln=0, align='C') | ||
if (i+1) >= 10 and (i+1) % 10 == 0: | ||
self.pdf.ln() | ||
|
||
|
||
def main(type): | ||
new_pdf = maths_worksheet_generator() | ||
seed_question = new_pdf.get_list_of_questions(type) | ||
new_pdf.make_question_page(seed_question) | ||
new_pdf.make_answer_page(seed_question) | ||
new_pdf.pdf.output("worksheet.pdf") | ||
|
||
|
||
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: ' | ||
'+: Addition; ' | ||
'-: Substration; ' | ||
'x: Multipication; ' | ||
'mix: Mixed; ' | ||
'(default: +)') | ||
args = parser.parse_args() | ||
main(args.type) |
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.