重新组装混乱的方法

时间:2019-03-18 16:18:36

标签: ruby

昨天,杰克(Jack)隔壁的那个孩子过来讲述他的不幸经历,想知道我是否可以帮助他解决他的问题。他一直在独自学习Ruby(在我的帮助下),并且经过几天的辛苦工作后才有了一个程序。在保存源代码之前,他不小心将其删除了。

幸运的是,他确实有打印输出。不幸的是,当他在学校时,他的妹妹用剪刀剪了他的打印输出。这是杰克(Jack)用她的手作拍摄的照片(在他用胶带将一些碎屑粘在一起之后)。

enter image description here

Jack希望我帮助他将程序重新组合在一起。我请他描述他正在研究的问题,但他非常沮丧,以至于他的回答完全是一团糟。

我整理了来自插条的信息,如下所示。

code = [
  ["def doit *args"],             # position fixed
  ["y = [a,c,d].reduce", :block],
  [:left, :right],
  [:left, :right],
  ["args.rotate!"],  
  ["z = yield(a,b)"],
  ["args.reverse!"],  
  ["a-2*b+7*c-3*d+30*e-2*y+6*z"], # position fixed
  ["end"],                        # position fixed
  ["doit(1,21,13,4,55)", :block]  # position fixed
]

第一行和最后三行的顺序很明显,但是我不知道其他行的顺序。钻屑中的两个必须在作业的左侧,两个在作业的右侧,两个是块。

在上面的数组中,由:left:right:block表示的六个插值在此哈希中给出:

pos = {
  left:  ["a,b,*_,c =", "d,e ="],
  right: ["args", "args.reverse"],
  block: ["{ |x,y| x+y }", "{ |x,y| x-y }"]  
} 

杰克说,唯一的切口#=> 275是他执行该方法时的返回值,所以我们可以写

rv = 275

我考虑过尝试不同的组合,但这似乎是没有希望的任务。当然,必须有某种方法可以使代码的重构自动化。

有人可以帮助我吗?建议可以,但我真的很想看看代码。

1 个答案:

答案 0 :(得分:2)

由于您坚持认为这是一种代码编写服务,并且您希望看到一些代码,所以我有时间消磨时间,并且我喜欢生成代码的代码,而且我们都不关心信誉得分,这是我重建小杰克辛勤工作的尝试:

# jack_gen.rb
["a,b,*_,c =", "d,e ="].permutation do |l1, l2|
  ["args", "args.reverse"].permutation do |r1, r2|
    ["{ |x,y| x+y }", "{ |x,y| x-y }"].permutation do |b1, b2|
      [
        "  y = [a,c,d].reduce #{b1}",
        "  #{l1} #{r1}",
        "  #{l2} #{r2}",
        "  args.rotate!",
        "  z = yield(a,b)",
        "  args.reverse!"
      ].permutation do |lines|
        source = [
          "def doit *args",
          *lines,
          "  a-2*b+7*c-3*d+30*e-2*y+6*z",
          "end",
          "doit(1,21,13,4,55) #{b2}"
        ].join("\n")

        rv = Object.new.instance_eval(source) rescue nil
        puts "\n#{source}\n#=> #{rv}" if rv == 275
      end
    end
  end
end

程序创建permutation的2个左侧,2个右侧,2个块和6条非固定线(2!×2!×2!×6!= 5,760种可能性) 。然后,将它们组合成由方法定义和方法调用组成的源字符串(以及固定行)。创建一个新对象,并使用instance_eval在该对象的上下文中评估该字符串,以抢救由于未定义变量而可能发生的异常(大约80%的生成方法是错误的)。

(方法调用的)结果为275时,将打印相应的源代码(以及结果)。

我们有8个这样的程序:

$ ruby jack_gen.rb

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  z = yield(a,b)
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  d,e = args.reverse
  z = yield(a,b)
  y = [a,c,d].reduce { |x,y| x-y }
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  z = yield(a,b)
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  z = yield(a,b)
  args.rotate!
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  z = yield(a,b)
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  d,e = args.reverse
  z = yield(a,b)
  y = [a,c,d].reduce { |x,y| x-y }
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  z = yield(a,b)
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275

def doit *args
  args.reverse!
  a,b,*_,c = args
  z = yield(a,b)
  args.rotate!
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275
这些程序中的

4个实际上是重复的,因为#{l1} #{r1} / #{l2} #{r2}Register Sole的提示)–足以使右边的变量,即" a,b,*_,c = #{r1}" / " d,e = #{r2}"

其余4个程序仅在z = yield(a, b)的位置不同。假设杰克按字母顺序分配变量,我们可以选择一个z = 之后 y =的变量:

def doit *args
  args.reverse!
  a,b,*_,c = args
  args.rotate!
  d,e = args.reverse
  y = [a,c,d].reduce { |x,y| x-y }
  z = yield(a,b)
  a-2*b+7*c-3*d+30*e-2*y+6*z
end
doit(1,21,13,4,55) { |x,y| x+y }
#=> 275