软工作业——四则运算生成器(scala 实现)

项目成员:刘跃群(3116005189)、张凯亮(3116005205)

项目仓库:https://github.com/wean2016/Myapp

PSP2.1表格

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning 计划 60 45
· Estimate · 估计这个任务需要多少时间 60 45
Development 开发 1420 1985
· Analysis · 需求分析 (包括学习新技术) 100 200
· Design Spec · 生成设计文档 20 20
· Design Review · 设计复审 (和同事审核设计文档) 30 30
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 100 100
· Design · 具体设计 50 55
· Coding · 具体编码 1000 1400
· Code Review · 代码复审 100 60
· Test · 测试(自我测试,修改代码,提交修改) 20 30
Reporting 报告 80 130
· Test Report · 测试报告 30 32
· Size Measurement · 计算工作量 20 21
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 30 77
合计   1560 2260

 设计实现过程及代码说明

 1. 生成表达式树

**
    * 构造表达式
    * @param symbolSum 剩余符号数
    * @param bound 表达式钟的数字不大于 bound
    * @return 生成的节点树的根
    */
  def createNodeTree(symbolSum:Int, bound:Int):Node = {
    if (symbolSum == 0){
      // 中间节点构造完成,生成叶子节点
      Node(Number.randomNumber(bound), null, null, 0, null)
    }else {
      val left = Random.nextInt(symbolSum)
      val right = symbolSum - left - 1
      var leftNode = createNodeTree(left,bound)
      var rightNode = createNodeTree(right,bound)
      // 本节点的符号
      var symbol = Symbol.values()(Random.nextInt(Symbol.values().length))
      // 如果是除号且右节点是 0 ,那么重新生成一个不是除号的符号
      if (symbol == Symbol.DIV && rightNode.value.a == 0){
        while (symbol == Symbol.DIV){
          symbol = Symbol.values()(Random.nextInt(Symbol.values().length))
        }
      }
      // 本节点的结果
      var value = Calculate.calc(leftNode.value,rightNode.value,symbol).get
      if (Number.isNeg(value)) {
        // 如果运算结果是负数,交换左右节点,并把结果取绝对值
        value = Number.abs(value)
        val tempNode = leftNode
        leftNode = rightNode
        rightNode = tempNode
      }
      val high = math.max(leftNode.high, rightNode.high) + 1
      // 生成本节点
      Node(value,leftNode,rightNode,high,symbol)
    }
  }

  2. 表达式树比较去重

  override def equals(obj: Any): Boolean =
     obj match {
      case that: Node =>
        if (that.symbol == null)  {if (symbol == null ) value.equals(that.value) else false}
        else if (symbol == null) false
        else if (left.equals(that.left) && right.equals(that.right) && symbol==that.symbol) true
        else if ((symbol==Symbol.ADD || symbol==Symbol.MULT) && left.equals(that.right) && right.equals(that.left)) true
        else false
      case _ => false

  }

  override def hashCode(): Int = {
    var result = value.hashCode()
    result = 31 * result + (if(left == null) 0 else left.hashCode())
    result = 31 * result + (if(right == null) 0 else right.hashCode())
    result = 31 * result + (if(symbol == null) 0 else symbol.hashCode())
    result
  }

  3. 打印表达式

  def printNode(node: Node):String = {
    if (node == null) return ""

    val midValue = if (node.symbol == null) node.value.toString else node.symbol.value
    // 左右的原始值
    var leftValue = printNode(node.left)
    var rightValue = printNode(node.right)
    // 判断是否要加括号,如果要,就加上去
    if (node.symbol != null && (node.symbol == Symbol.MULT || node.symbol == Symbol.DIV)){
      val leftSymbol = node.left.symbol
      val rightSymbol = node.right.symbol
      if (leftSymbol != null && (leftSymbol == Symbol.ADD || leftSymbol == Symbol.SUB)) leftValue = Bracket.leftBracket.value + leftValue + Bracket.rightBracket.value
      if (rightSymbol != null && (rightSymbol == Symbol.ADD || rightSymbol == Symbol.SUB)) rightValue = Bracket.leftBracket.value + rightValue + Bracket.rightBracket.value
    }
    leftValue + midValue + rightValue
  }

  4. 从字符串生成表达式树(用于计算成绩时构造表达式树)

def fromString(s:String): Node = {
    // 克隆输入的字符串,实现函数式编程
    var value = new String(s.toCharArray)
    // 给符号都加上空格
    Symbol.values().foreach(symbol => {
      if (symbol.value.equals("+")){
        value = value.replaceAll("\\+", " %s ".format(symbol.value))
      }else{
        value = value.replaceAll(symbol.value, " %s ".format(symbol.value))
      }
    })
    // 给括号都加上空格
    Bracket.values().foreach(bracket => value = value.replaceAll("\\" + bracket.value, " %s ".format(bracket.value)))
    //去空格生成元素数组
    val factor = value.split(" ").toStream.map(s => s.trim).filter(s => !s.isEmpty).toList
    val nodeStack: util.Stack[Node] = new util.Stack[Node]
    val symbolStack: util.Stack[String] = new util.Stack[String]
    for (f <- factor) {
      // 尝试转换成数字
      val value = Number.fromString(f)
      if (value.isDefined) {
        // 是数字
        nodeStack.push(Node(value.get, null, null, 0, null))
      } else {
        // 是符号
        var signal = true
        while (!symbolStack.empty() && !f.equals(Bracket.leftBracket.value) && !((f.equals(Symbol.MULT.value) || f.equals(Symbol.DIV.value)) && (symbolStack.peek().equals(Symbol.ADD.value) || symbolStack.peek().equals(Symbol.SUB.value))) && !(!f.equals(Bracket.rightBracket.value) && symbolStack.peek().equals(Bracket.leftBracket.value)) && signal) {
          val symbol = symbolStack.pop()
          if (symbol.equals(Bracket.leftBracket.value) && f.equals(Bracket.rightBracket.value)) {
            signal = false
          } else {

            val rightNode = nodeStack.pop()
            val leftNode = nodeStack.pop()
            val sym = symbol match {
              case "+" => Symbol.ADD
              case "-" => Symbol.SUB
              case "×" => Symbol.MULT
              case "÷" => Symbol.DIV
              case _ => sys.error("非法运算符!")
            }
            val result = Calculate.calc(leftNode.value, rightNode.value, sym)
            if (result.isEmpty) {
              sys.error("存在不符合规范的算术表达式!")
            }
            val high = math.max(leftNode.high, rightNode.high) + 1
            nodeStack.push(Node(result.get, leftNode, rightNode, high, sym))
          }
        }
        if (!f.equals(Bracket.rightBracket.value)) {
          symbolStack.push(f)
        }
      }
    }
    while(!symbolStack.isEmpty){
      val symbol = symbolStack.pop()
      if (!symbol.equals(Bracket.leftBracket.value)){

        val rightNode = nodeStack.pop()
        val leftNode = nodeStack.pop()
        val sym = symbol match {
          case "+" => Symbol.ADD
          case "-" => Symbol.SUB
          case "×" => Symbol.MULT
          case "÷" => Symbol.DIV
          case _ => sys.error("非法运算符!")
        }
        val result = Calculate.calc(leftNode.value, rightNode.value, sym)
        if (result.isEmpty) {
          sys.error("存在不符合规范的算术表达式!")
        }
        val high = math.max(leftNode.high, rightNode.high) + 1
        nodeStack.push(Node(result.get, leftNode, rightNode, high, sym))
      }
    }
    nodeStack.pop()
  }

  

测试运行

生成问题

生成答案

生成成绩

把一些题目的答案改成错误

项目小结

通过结对编程,两个人互相修改代码,共同提高了能力,也写出了更好的代码。确实是种不错的写代码方式

posted @ 2018-09-27 00:32  wean2018  阅读(706)  评论(3编辑  收藏  举报