使用python的turtle库给小学生出题

@开发环境说明:turtle界面在2k的2560*1440分辨率下开发,其它分辨率不一定完全兼容

1 设计过程

1.1 设计验证题目是否合理的函数

根据出题条件,出题时要验证题目是否合理,这里已经保证了左边的值,右边的值和运算符都符合要求。具体的判断如下即可保证题目一定正确:

  • 针对加法:如果结果result>99则不符合出题条件,返回False
  • 针对减法:如果结果result<0则不符合出题条件,返回False
  • 针对乘法:如果结果result>99则不符合出题条件,返回False
  • 针对除法:如果分母=0,或者除了后不是整数,返回False
  • 其它情况返回True,result

完整的代码如下:

def check_problem(left_value, math_operation, right_value):
    """
    检查是否符合出题条件
    :param left_value: 左边的值
    :param math_operation: 运算符
    :param right_value: 右边的值
    :return: 如果符合则返回True,不符合返回Flase,以及计算结果result
    """
    result = None
    if math_operation == "+":
        result = left_value + right_value
        if result > 99:
            return False, result
    elif math_operation == "-":
        result = left_value - right_value
        if result < 0:
            return False, result
    elif math_operation == "x":
        result = left_value * right_value
        if result > 99:
            return False, result
    elif math_operation == "÷":
        if (right_value == 0) or (left_value % right_value != 0):
            return False, result
        result = int(left_value / right_value)
    return True, result

1.2 生成试卷

因为试卷是5行3列的关系,所以可以使用二维列表保存5行3列结构的数据,左边的值、右边的值、运算符和计算结果都用二维列表表示。

使用python的random库的chioce方法:


for i in range(5):

​ for j in range(3):

​ (针对第i行第j列)

​ step 1——从("+", "-", "x", "÷")中使用random.choice()方法选择运算符,并且把运算符保存到二维列表math_operation_list中

​ step 2——确定运算符后,使用random.choice(range(0, 100))随机生成左边的值和右边的值,并且对取值进行验证是否合理,直到 生成合理的值为止。

​ step 3——保存左边的值到二维列表left_list中,保存右边的值到二维列表right_list中,对应的计算结果也保存到二维列表result_list 中。

​ step 4——返回左边的值、右边的值、运算符和计算结果的二维列表left_list, right_list, math_operation_list, result_list,试卷生成 完毕!


完整代码如下:

def gennerate_test_paper():
    """生成试卷"""
    left_list = []  # 左边的值
    right_list = []  # 右边的值
    math_operation_list = []  # 运算符
    result_list = []  # 计算结果
    for i in range(5):
        left_list.append([])
        right_list.append([])
        math_operation_list.append([])
        result_list.append([])
        for j in range(3):
            _temp_math_operation = random.choice(("+", "-", "x", "÷"))
            math_operation_list[i].append(_temp_math_operation)
            while True:
                _temp_left_list_value = random.choice(range(0, 100))
                _temp_right_list_value = random.choice(range(0, 100))

                check_problem_state, _temp_result = check_problem(left_value=_temp_left_list_value,
                                                                  math_operation=_temp_math_operation,
                                                                  right_value=_temp_right_list_value)
                if check_problem_state:
                    result_list[i].append(_temp_result)
                    break
            left_list[i].append(_temp_left_list_value)
            right_list[i].append(_temp_right_list_value)
    return left_list, right_list, math_operation_list, result_list

1.3 检查试卷是否有重复项

检查试卷是否有重复项是用的“暴力查找的方式”,把所有的题目都两两检索一遍(除了自身),检查是否完全一样,时间复杂度是

\[i^2j^2,其中i为行数,j为列数 \]

时间复杂度虽然很高,但考虑到这里的i=5和j=3很小,所以暴力查找检查是否有重复项即可。

完整的代码如下:

def check_duplicate_problems(left_list, math_operation_list, right_list):
    """
    检查是否有重复题目
    :param left_list:
    :param math_operation_list:
    :param right_list:
    :return: 如果没有重复返回True,否则返回False
    """

    for i in range(5):
        for j in range(3):
            for k in range(5):
                for l in range(3):
                    if i != k and j != l:
                        if left_list[i][j] == left_list[k][l] and math_operation_list[i][j] == math_operation_list[k][
                            l] and \
                                right_list[i][j] == right_list[k][l]:
                            return False
    return True

while not check_duplicate_problems_state:
    """检查试卷是否有重复项"""
    left_list, right_list, math_operation_list, result_list = gennerate_test_paper()
    check_duplicate_problems_state = check_duplicate_problems(left_list, math_operation_list, right_list)

1.4 使用turtle库画出试卷

  • step 1——画标题

    goto到坐标(-450,500)画标题

  • step 2——画“试卷”和下划线,“答案”和下划线

    goto到坐标(-450,400)画“试题“和对应下划线;goto到坐标(-450,0)画“答案“和对应下划线;

  • step 3——画具体的试卷内容和答案内容

    初始化试卷内容和答案内容的坐标

    for i in range(5):

    ​ 每画一行纵坐标下移

    ​ for j in range(3):

    ​ 每画一列横坐标右移

    ​ 画对应i行j列的“左边的值 运算符 右边的值”

    ​ 画"="号

    ​ 画“方框”

    ​ 对于答案的区域,还要在“方框”区域画上答案

完整的代码如下:

"""标题"""
penup()
goto(x=-450, y=500)
write(arg="某小学数学试卷       姓名:_________      成绩:_________", move=True, align='left',
      font=('微软雅黑', 20, 'normal'))

"""试卷"""
penup()
goto(x=-450, y=400)
write(arg="试题", move=True, align='left', font=('微软雅黑', 20, 'normal'))

penup()
goto(x=-450, y=400)
write(arg="______________________________________________________________________________", move=True, align='left',
      font=('微软雅黑', 20, 'normal'))

"""答案"""
penup()
goto(x=-450, y=0)
write(arg="答案", move=True, align='left', font=('微软雅黑', 20, 'normal'))

penup()
goto(x=-450, y=0)
write(arg="______________________________________________________________________________", move=True, align='left',
      font=('微软雅黑', 20, 'normal'))

y_paper = 400
y_answer = 0
for i in range(5):
    """5行"""
    x_paper = -700
    y_paper = y_paper - 50

    x_answer = -700
    y_answer = y_answer - 50
    for j in range(3):
        x_paper = x_paper + 300
        x_answer = x_answer + 300
        """3列"""
        arg = f"{left_list[i][j]}  {math_operation_list[i][j]}  {right_list[i][j]}"

        """试卷"""
        penup()
        goto(x=x_paper, y=y_paper)
        write(arg=arg, move=True, align='left', font=('微软雅黑', 20, 'normal'))
        # =号
        penup()
        goto(x=x_paper + 150, y=y_paper)
        write(arg="=", move=True, align='left', font=('微软雅黑', 20, 'normal'))
        # 方框
        goto(x=x_paper + 200, y=y_paper)
        pendown()
        plow_n(n=4, forward_len=45)
        penup()

        """答案"""
        penup()
        goto(x=x_answer, y=y_answer)
        write(arg=arg, move=True, align='left', font=('微软雅黑', 20, 'normal'))
        # =号
        penup()
        goto(x=x_answer + 150, y=y_answer)
        write(arg="=", move=True, align='left', font=('微软雅黑', 20, 'normal'))

        # 方框
        goto(x=x_answer + 200, y=y_answer)
        pendown()
        plow_n(n=4, forward_len=45)
        penup()

        # 答案
        penup()
        goto(x=x_answer + 210, y=y_answer)
        write(arg=f"{result_list[i][j]}", move=True, align='left', font=('微软雅黑', 20, 'normal'))

exitonclick()

2 结果展示

image
image

3 完整代码为

"""
使用Python的海龟库完成小学数学题试卷的出题工作,要求:
(1)上半部分为题目,下半部分为答案。
(2)试题中,计算结果显示为方框。答案中,在方框中出现结果。题目和答案的顺序对应。
(3)题目每行3题,共5行。答案数量相同。
(4)题目随机生成。(建议使用random库中的sample, choice函数)
(5)不得有重复的题目(即两道题目的运算符相同、运算符左/右的操作数分别相同,结果也相同的题目)。
(6)题目分为加减乘除四类,运算过程和结果均为两位以内的整数(0到99)。
(7)完成上述代码功能(提交py代码),同时完成较为简单的软件设计文档(提交pdf即可),文档包括设计思路、关键代码解释、效果图等。
"""
from turtle import *
import random

screensize(1000, 1000)
speed(0)


def plow_n(n, forward_len):
    """
    画N边形
    :param forward_len: 决定画的大小
    :param n:决定N变形
    :return:
    """
    angle = 360 / n
    for i in range(n):
        forward(forward_len)
        left(angle)


def check_problem(left_value, math_operation, right_value):
    """
    检查是否符合出题条件
    :param left_value: 左边的值
    :param math_operation: 运算符
    :param right_value: 右边的值
    :return: 如果符合则返回True,不符合返回Flase,以及计算结果result
    """
    result = None
    if math_operation == "+":
        result = left_value + right_value
        if result > 99:
            return False, result
    elif math_operation == "-":
        result = left_value - right_value
        if result < 0:
            return False, result
    elif math_operation == "x":
        result = left_value * right_value
        if result > 99:
            return False, result
    elif math_operation == "÷":
        if (right_value == 0) or (left_value % right_value != 0):
            return False, result
        result = int(left_value / right_value)
    return True, result


def check_duplicate_problems(left_list, math_operation_list, right_list):
    """
    检查是否有重复题目
    :param left_list:
    :param math_operation_list:
    :param right_list:
    :return: 如果没有重复返回True,否则返回False
    """

    for i in range(5):
        for j in range(3):
            for k in range(5):
                for l in range(3):
                    if i != k and j != l:
                        if left_list[i][j] == left_list[k][l] and math_operation_list[i][j] == math_operation_list[k][
                            l] and \
                                right_list[i][j] == right_list[k][l]:
                            return False
    return True


def gennerate_test_paper():
    """生成试卷"""
    left_list = []  # 左边的值
    right_list = []  # 右边的值
    math_operation_list = []  # 运算符
    result_list = []  # 计算结果
    for i in range(5):
        left_list.append([])
        right_list.append([])
        math_operation_list.append([])
        result_list.append([])
        for j in range(3):
            _temp_math_operation = random.choice(("+", "-", "x", "÷"))
            math_operation_list[i].append(_temp_math_operation)
            while True:
                _temp_left_list_value = random.choice(range(0, 100))
                _temp_right_list_value = random.choice(range(0, 100))

                check_problem_state, _temp_result = check_problem(left_value=_temp_left_list_value,
                                                                  math_operation=_temp_math_operation,
                                                                  right_value=_temp_right_list_value)
                if check_problem_state:
                    result_list[i].append(_temp_result)
                    break
            left_list[i].append(_temp_left_list_value)
            right_list[i].append(_temp_right_list_value)
    return left_list, right_list, math_operation_list, result_list


left_list = []  # 左边的值
right_list = []  # 右边的值
math_operation_list = []  # 运算符
result_list = []  # 计算结果
check_duplicate_problems_state = False  # 刚开始是False
while not check_duplicate_problems_state:
    """检查试卷是否有重复项"""
    left_list, right_list, math_operation_list, result_list = gennerate_test_paper()
    check_duplicate_problems_state = check_duplicate_problems(left_list, math_operation_list, right_list)

print(f"left_list:{left_list}")
print(f"right_list:{right_list}")
print(f"math_operation_list:{math_operation_list}")

"""标题"""
penup()
goto(x=-450, y=500)
write(arg="某小学数学试卷       姓名:_________      成绩:_________", move=True, align='left',
      font=('微软雅黑', 20, 'normal'))

"""试卷"""
penup()
goto(x=-450, y=400)
write(arg="试题", move=True, align='left', font=('微软雅黑', 20, 'normal'))

penup()
goto(x=-450, y=400)
write(arg="______________________________________________________________________________", move=True, align='left',
      font=('微软雅黑', 20, 'normal'))

"""答案"""
penup()
goto(x=-450, y=0)
write(arg="答案", move=True, align='left', font=('微软雅黑', 20, 'normal'))

penup()
goto(x=-450, y=0)
write(arg="______________________________________________________________________________", move=True, align='left',
      font=('微软雅黑', 20, 'normal'))

y_paper = 400
y_answer = 0
for i in range(5):
    """5行"""
    x_paper = -700
    y_paper = y_paper - 50

    x_answer = -700
    y_answer = y_answer - 50
    for j in range(3):
        x_paper = x_paper + 300
        x_answer = x_answer + 300
        """3列"""
        arg = f"{left_list[i][j]}  {math_operation_list[i][j]}  {right_list[i][j]}"

        """试卷"""
        penup()
        goto(x=x_paper, y=y_paper)
        write(arg=arg, move=True, align='left', font=('微软雅黑', 20, 'normal'))
        # =号
        penup()
        goto(x=x_paper + 150, y=y_paper)
        write(arg="=", move=True, align='left', font=('微软雅黑', 20, 'normal'))
        # 方框
        goto(x=x_paper + 200, y=y_paper)
        pendown()
        plow_n(n=4, forward_len=45)
        penup()

        """答案"""
        penup()
        goto(x=x_answer, y=y_answer)
        write(arg=arg, move=True, align='left', font=('微软雅黑', 20, 'normal'))
        # =号
        penup()
        goto(x=x_answer + 150, y=y_answer)
        write(arg="=", move=True, align='left', font=('微软雅黑', 20, 'normal'))

        # 方框
        goto(x=x_answer + 200, y=y_answer)
        pendown()
        plow_n(n=4, forward_len=45)
        penup()

        # 答案
        penup()
        goto(x=x_answer + 210, y=y_answer)
        write(arg=f"{result_list[i][j]}", move=True, align='left', font=('微软雅黑', 20, 'normal'))

exitonclick()

posted @ 2023-03-21 15:45  JaxonYe  阅读(199)  评论(0编辑  收藏  举报