zoukankan      html  css  js  c++  java
  • python 实现小学四则运算

    小学四则运算

    1. 项目要求

    • 随机生成小学内的四则运算式子,不包含负数
    • 支持真分数运算

    2. PSP流程表格

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 20 30
    Development 开发 300 420
    Analysis 需求分析 (包括学习新技术) 30 45
    Coding Standard 代码规范 (制定合适的规范) 20 25
    Design 具体设计 30 40
    Coding 具体编码 30 60
    Code Review 代码复审 30 30
    Test 测试 40 60
    Reporting 报告 20 30
    合计 520 740

    3. 解题思路描述

      该问题总体可分为两部分: 第一部分生成算式, 第二部分计算算式

    3.1 第一部分

      首先,随机生成操作数和运算符,通过参数设置操作数的大小上限、运算符的数量以及是否含分数。
      接着,在算式中插入括号,括号插在减法的减数位置上或者乘除法附近的加减子算式中。
      最后,将算式拼接起来。

    3.2 第二部分

      通过栈先将算式转为后缀表达式即逆波兰式,之后再计算出算式的结果,结果保留分数形式。

    4. 代码说明

    4.1 项目文件结构
    模块 功能
    main.py 主函数
    stack.py 栈实现
    formula_library.py 存放算式和正确答案
    methods.py 包含美化命令行界面、获取参数、输出算式、核对答案
    generate_ari.py 生成算式
    calculator.py 计算算式结果,含中缀表达式转后缀表达式

      核心模块为generate_ari类和calculator类

      

    4.2 部分模块代码

    generate_ari类

    点击查看代码
    import re
    import random
    from fractions import Fraction
    
    
    class GenerateAri():
        '''生成算术表达式'''
        def __init__(self, maxNum=10, optNum=1, hasFraction=False):
            self.init_operators(optNum, hasFraction)
            self.init_operands(maxNum, hasFraction)
            self.merge_expression()
    
        def init_operand(self, maxNum, hasFraction):
            '''生成随机数'''
            if hasFraction:
                while True:
                    numerator = random.randint(1, maxNum)
                    denominator = random.randint(1, maxNum)
                    if numerator != denominator:
                        break
                return Fraction(numerator, denominator)
            else:
                return random.randint(2, maxNum)
    
        def init_operators(self, optNum, hasFraction):
            '''生成操作符'''
            if hasFraction:
                self.opts = [random.choice(['+', '-', '×', '÷']) for i in range(optNum)]
            else:
                self.opts = [random.choice(['+', '-', '×']) for i in range(optNum)]
            self.opts.append('=')
            self.insert_bracket()
    
        def init_operands(self, maxNum, hasFraction):
            '''生成操作数'''
            self.nums = [str(self.init_operand(maxNum, hasFraction)) for i in range(len(self.opts))]
    
        def insert_bracket(self):
            '''插入括号'''
            optsNum = len(self.opts)
            leftBrackets = [''] * optsNum
            rightBrackets = [''] * optsNum
            begin, index = 0, 0
            strOpt = ''.join(self.opts)
    
            while begin < optsNum-1:
                if self.opts[begin] == '+':
                    begin += 1
                    continue
    
                search = None
                if begin-index > 1:
                    if self.opts[begin] in ['×', '÷']:
                        search = re.search(r'[+|-]', strOpt[index:begin][::-1])
                        if search:
                            rightBrackets[begin] = ')'
                            leftInd = random.randint(index, begin-search.start()-1)
                            leftBrackets[leftInd] = '('
                            index = begin
    
                if index >= optsNum-2:
                    break
    
                search = None
                if self.opts[begin] in ['×', '÷', '-']:
                    if self.opts[begin] == '÷':
                        search = re.search(r'[×|÷|+|-]', strOpt[begin+1:])
                    else:
                        search = re.search(r'[+|-]', strOpt[begin+1:])
                    if search:
                        leftBrackets[begin+1] = '('
                        rightInd = random.randint(begin+2+search.start(), optsNum-1)
                        rightBrackets[rightInd] = ')'
                        index = rightInd
                        begin = index
                    else:
                        begin += 1
    
            self.brackets = [leftBrackets, rightBrackets]
    
        def merge_expression(self):
            '''合并表达式'''
            self.expression = [
                ''.join([i, j, k, l])
                for i, j, k, l in zip(self.brackets[0], self.nums, self.brackets[1], self.opts)
                ]
            self.expression = ''.join(self.expression)
            for _ in set(re.findall(r'[=|×|÷|+|-]', self.expression)):
                self.expression = self.expression.replace(_, ' {} '.format(_))
    
    

      
    calculator类

    点击查看代码
    import stack
    from fractions import Fraction
    
    
    class Calculator:
        def __init__(self):
            self.operators = ['+', '-', '×', '÷', '(', ')', '=']
            self.priority = {'+': 1, '-': 1, '×': 2, '÷': 2, '(': 99}
    
        def getResult(self):
            '''计算结果'''
            valueStack = []
            for item in self.suffixExp:
                if item in self.operators:
                    x2 = valueStack.pop()
                    x1 = valueStack.pop()
                    result = self.calculate(x1, x2, item)
                    if result < 0:
                        return '-1'
                    valueStack.append(str(result))
                else:
                    valueStack.append(item)
            return valueStack[0]
    
        def calculate(self, x1, x2, opt):
            '''操作数出栈进行计算'''
            if '/' in x1 or '/' in x2:
                x1 = Fraction(x1)
                x2 = Fraction(x2)
            else:
                x1 = eval(x1)
                x2 = eval(x2)
    
            if opt == '+':
                return x1 + x2
            elif opt == '-':
                return x1 - x2
            elif opt == '×':
                return x1 * x2
            elif opt == '÷':
                return Fraction(x1 / x2).limit_denominator() if x2 != 0 else -1
            else:
                return -1
    
        def infix2suffix(self, ari):
            '''中缀表达式转后缀表达式'''
            self.suffixExp = []
            optStack = stack.Stack()
            exps = list(zip(ari.brackets[0], ari.nums, ari.brackets[1], ari.opts))
            for exp in exps:
                for element in exp:
                    if element == '=':
                        while not optStack.is_empty():
                            popChar = optStack.pop()
                            if popChar != '(':
                                self.suffixExp.append(popChar)
                        break
                    if element in self.operators:
                        if optStack.is_empty():
                            optStack.push(element)
                        else:
                            if element == ')':
                                while not optStack.is_empty() and optStack.peek() != '(':
                                    popChar = optStack.pop()
                                    self.suffixExp.append(popChar)
                                if optStack.size() > 0:
                                    optStack.pop()
                            elif self.priority[optStack.peek()] < self.priority[element]:
                                optStack.push(element)
                            else:
                                if optStack.peek() == '(':
                                    optStack.push(element)
                                else:
                                    while not optStack.is_empty() and self.priority[optStack.peek()] >= self.priority[element] and optStack.peek() != '(':
                                        popChar = optStack.pop()
                                        self.suffixExp.append(popChar)
                                    optStack.push(element)
                    else:
                        if element != '':
                            self.suffixExp.append(element)
    
    

      
    methods模块

    点击查看代码
    import sys
    import time
    import datetime
    from fractions import Fraction
    
    
    def entrance():
        '''程序开始提示语'''
        print('{:-^60}'.format(''))
        print('{:^60}'.format(''))
        print('{:^55}'.format('四 则 运 算(不 含 负 数)'))
        print('{:^60}'.format(''))
        print('{:-^60}'.format(''))
    
        for word in '  欢迎使用【四则运算】v1.0':
            sys.stdout.write(word)
            sys.stdout.flush()
            time.sleep(0.2)
        time.sleep(1)
        sys.stdout.write('
    {:<50}
    '.format(''))
        sys.stdout.flush()
    
    
    def getParameters():
        '''获取用户输入的算式参数'''
        for word in '  请输入您希望的算式参数:':
            sys.stdout.write(word)
            sys.stdout.flush()
            time.sleep(0.2)
        time.sleep(0.5)
        print()
        while True:
            print('{:^60}'.format('*'*30))
            try:
                formulaNum = int(input('{0:15} {1:>15} | '.format(' ', '算式数量(>=1)')))
                assert formulaNum >= 1
                maxNum = int(input('{0:15} {1:>15} | '.format(' ', '数值上限(>=10)')))
                assert maxNum >= 10
                operatorNum = int(input('{0:15} {1:>14} | '.format(' ', '运算符个数(>=1)')))
                assert operatorNum >= 1
                hasFraction = int(input('{0:15} {1:>13} | '.format(' ', '是否包含分数(0, 1)')))
                assert hasFraction == 0 or hasFraction == 1
                print('{:^60}'.format('*'*30))
            except AssertionError:
                print('{:^60}'.format('*'*30))
                print('  ❌ 输入错误, 请输入正确范围下的数值')
                print('{:-^60}'.format(''))
                print('  请输入您希望的算式参数:')
            except ValueError:
                print('{:^60}'.format('*'*30))
                print('  ❌ 输入错误, 请输入正确的数值')
                print('{:-^60}'.format(''))
                print('  请输入您希望的算式参数:')
            else:
                print('{:-^60}'.format(''))
                break
        return formulaNum, maxNum, operatorNum, hasFraction
    
    
    def getOutputMode():
        '''获取输出模式'''
        while True:
            print('{:^51}'.format('请选择算式输出模式'))
            print('{0}
    {1}'.format('    1、普通模式', '    2、问答模式'))
    
            try:
                mode = int(input('  请选择: '))
                assert 1 <= mode <= 2
            except AssertionError:
                print(' ❌ 输入错误, 请输入正确范围下的数值')
                print('{:-^60}'.format(''))
            except ValueError:
                print(' ❌ 输入错误, 请输入正确的数值')
                print('{:-^60}'.format(''))
            else:
                print('{:-^60}'.format(''))
                break
        return mode
    
    
    def checkAnswer(userAnswer, library, titleNum=0):
        '''核对答案'''
        if isinstance(userAnswer, list):
            checks = []
            for result in userAnswer:
                try:
                    result = str(Fraction(result).limit_denominator())
                    checks = checks + [True] if result == library.results[titleNum] else checks + [False]
                except Exception:
                    checks = checks + [False]
                finally:
                    titleNum += 1
            return checks
        else:
            try:
                check = True
                userAnswer = str(Fraction(userAnswer).limit_denominator())
                if userAnswer != library.results[titleNum]:
                    check = False
            except ValueError:
                check = False
            finally:
                return check
    
    
    def outputFormula(mode, library):
        '''输出算式'''
        if mode == 1:
            userAnswers = []
            start = datetime.datetime.now()
            for num, exp in enumerate(library.formulas):
                userAnswers = userAnswers + [input('({}) {}'.format(num+1, exp))]
            end = datetime.datetime.now()
            checks = checkAnswer(userAnswers, library)
            errorIndex = [ind for ind, value in enumerate(checks) if value is False]
            if len(errorIndex) > 0:
                print(' ❌ 错误 {} 题: '.format(len(errorIndex)), end='')
                for ind in errorIndex:
                    print('({})'.format(ind+1), end=' ')
                print()
                print(' ⭕ 正确答案: ', end='')
                for ind in errorIndex:
                    print('({}) {}'.format(ind+1, library.results[ind]), end=' ')
                print()
            else:
                print(' ✅ 恭喜你全部答对了')
            print()
            print('正确率: {:.2f}%'.format(100*float((library.formulaNum()-len(errorIndex))/library.formulaNum())))
            print('耗时: {}'.format(end-start))
    
        else:
            errorCount = 0
            start = datetime.datetime.now()
            for num, exp in enumerate(library.formulas):
                userAnswer = input('({}) {}'.format(num+1, exp))
                if checkAnswer(userAnswer, library, num):
                    print('⭕ 回答正确!!! 正确答案是: {}'.format(library.results[num]))
                else:
                    errorCount += 1
                    print('❌ 回答错误!!! 正确答案是: {}'.format(library.results[num]))
            end = datetime.datetime.now()
            print()
            print('正确率: {:.2f}%'.format(100*float((library.formulaNum()-errorCount)/library.formulaNum())))
            print('耗时: {}'.format(end-start))
    
    

      

    5. 测试运行

    5.1 正确运行

    image
    image
    image
    image

      

    5.2 错误输入

    image
    image
    image

  • 相关阅读:
    pyhton 线程锁
    python 守护线程
    python 线程
    python 判断文件的字符编码
    python 进程管道
    python 进程池
    webpack学习(一)起步安装
    最近特别喜欢的一首歌
    你真的了解回流和重绘吗?
    你了解SEO中的时效性吗?
  • 原文地址:https://www.cnblogs.com/Lincoln-Wong/p/15348545.html
Copyright © 2011-2022 走看看