Дамяна обнови решението на 14.11.2012 02:39 (преди около 12 години)
+class Unary
+ attr_accessor :expr
+
+ def initialize(expr)
+ @expr = expr
+ end
+
+ def evaluate(env = {})
+ case expr[0]
+ when :-
+ Negation.new(expr[1]).evaluate(env)
+ when :sin
+ Sine.new(expr[1]).evaluate(env)
+ when :cos
+ Cosine.new(expr[1]).evaluate(env)
+ end
+ end
+end
+
+class Binary
+ attr_accessor :expr
+
+ def initialize(expr)
+ @expr = expr
+ end
+
+ def evaluate(env = {})
+ case expr[1]
+ when :+
+ Addition.new(expr[0], expr[2]).evaluate(env)
+ when :*
+ Multiplication.new(expr[0], expr[2]).evaluate(env)
+ end
+ end
+end
+
+class Number
+ def initialize(value)
+ @value = value
+ end
+
+ def evaluate(env = {})
+ @value
+ end
+end
+
+class Variable
+ def initialize(variable)
+ @variable = variable
+ end
+
+ def evaluate(env = {})
+ env[@variable]
+ end
+end
+
+class Addition
+ def initialize(left, right)
+ @left = left.is_a?(Numeric) ? Number.new(left) : Variable.new(left)
+ @right = right.is_a?(Numeric) ? Number.new(right) : Variable.new(right)
+ end
+
+ def evaluate(env = {})
+ @left.evaluate(env) + @right.evaluate(env)
+ end
+end
+
+class Multiplication
+ def initialize(left, right)
+ @left = left.is_a?(Numeric) ? Number.new(left) : Variable.new(left)
+ @right = right.is_a?(Numeric) ? Number.new(right) : Variable.new(right)
+ end
+
+ def evaluate(env = {})
+ @left.evaluate(env) * @right.evaluate(env)
+ end
+end
+
+class Negation
+ def initialize(operant)
+ @operant = operant.is_a?(Numeric) ? Number.new(operant) : Variable.new(operant)
+ end
+
+ def evaluate(env = {})
+ -@operant.evaluate(env)
+ end
+end
+
+class Sine
+ def initialize(operant)
+ @operant = operant.is_a?(Numeric) ? Number.new(operant) : Variable.new(operant)
+ end
+
+ def evaluate(env = {})
+ Math.sin(@operant.evaluate(env))
+ end
+end
+
+class Cosine
+ def initialize(operant)
+ @operant = operant.is_a?(Numeric) ? Number.new(operant) : Variable.new(operant)
+ end
+
+ def evaluate(env = {})
+ Math.cos(@operant.evaluate(env))
+ end
+end
+
+class Expr
+ attr_accessor :expr
+
+ def initialize(expr)
+ @expr = expr
+ end
+
+ def Expr.build(sexpr)
+ expr = Expr.create(sexpr).flatten(1)
+ Expr.new(expr)
+ end
+
+ def Expr.create(sexpr)
+ expr = []
+ case sexpr[0]
+ when :number then expr = [sexpr[1]]
+ when :variable then expr = [sexpr[1]]
+ when :+ then expr << (create(sexpr[2]).unshift(create(sexpr[1]) | [sexpr[0]])).flatten(1)
+ when :* then expr << (create(sexpr[2]).unshift(create(sexpr[1]) | [sexpr[0]])).flatten(1)
+ when :- then expr << ([sexpr[0]] | create(sexpr[1]))
+ when :sin then expr << ([sexpr[0]] | create(sexpr[1]))
+ when :cos then expr << ([sexpr[0]] | create(sexpr[1]))
+ end
+ end
+
+ def ==(other)
+ return self.expr == other.expr
+ end
+
+ def evaluate(env = {})
+ case expr.length
+ when 1
+ return expr[0]
+ when 2
+ operant = expr[1].is_a?(Array) ? Expr.new(expr[1]).evaluate(env) : expr[1]
+ return Unary.new([expr[0], operant]).evaluate(env)
+ when 3
+ left = expr[0].is_a?(Array) ? Expr.new(expr[0]).evaluate(env) : expr[0]
+ right = expr[2].is_a?(Array) ? Expr.new(expr[2]).evaluate(env) : expr[2]
+ return Binary.new([left, expr[1], right]).evaluate(env)
+ end
+ end
+
+ def exact?
+ case expr.length
+ when 1
+ return true
+ when 2
+ return expr[1].is_a?(Array) ? Expr.new(expr[1]).exact? : expr[1].is_a?(Numeric)
+ when 3
+ left = expr[0].is_a?(Array) ? Expr.new(expr[0]).exact? : expr[0].is_a?(Numeric)
+ right = expr[2].is_a?(Array) ? Expr.new(expr[2]).exact? : expr[2].is_a?(Numeric)
+ left and right
+ end
+ end
+
+ def simplify
+ evaluate if exact?
+ end
+end