在ruby中使用组合逻辑的麻烦

时间:2010-11-30 20:50:37

标签: ruby logic

写一个简单的蒙特卡罗模拟中子束。几何逻辑出现问题(无论是某种环境还是其他环境)。我的问题是Ruby似乎是按顺序处理条件并保持它的第一个值。

下面的代码很好地说明了这一点:

def checkPosition(*args)

  polyCylRad = 2.5
  polyCylFr = 15
  polyCylB = -2.0
  borPolyBoxL = 9.0 / 2
  pbCylRad = 3.0
  pbBoxL = 10.0 / 2
  cdBoxL = 9.5 / 2

  position = Array.new
  material = String.new

  args.each do |item|
    position << item.inspect.to_f
  end
  xSquared = position.at(0) ** 2
  ySquared = position.at(1) ** 2
  zSquared = position.at(2) ** 2
  modX = Math.sqrt(xSquared)
  modY = Math.sqrt(ySquared)
  modZ = Math.sqrt(zSquared)

  puts xSquared
  puts Math.sqrt(ySquared + zSquared) <= polyCylRad
  puts (position.at(0) >= polyCylB)
  puts (position.at(0) <= polyCylFr)
  puts (position.at(0) >= polyCylB)and(position.at(0) <= polyCylFr)
  puts (position.at(0) <= polyCylFr)and(position.at(0) >= polyCylB)

  puts zSquared


  polyCylinder = (Math.sqrt(ySquared + zSquared) <= polyCylRad)and((position.at(0) >= polyCylB)and(position.at(0) <= polyCylFr) )
  puts polyCylinder
  borPolyBox = ((modX <= borPolyBoxL)or(modY < borPolyBoxL)or(modZ <= borPolyBoxL)) and not((modX >= cdBoxL)or(modY >= cdBoxL)or(modZ >= cdBoxL)) and not(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  puts borPolyBox
  cadmiumShield = ((modX <= cdBoxL)or(modY < cdBoxL)or(modZ <= cdBoxL)) and not((modX >= pbBoxL)or(modY >= pbBoxL)or(modZ >= pbBoxL)) and not(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  puts cadmiumShield
  leadShield = ( ((modX <= pbBoxL)or(modY <= pbBoxL)or(modZ <= pbBoxL)) or ((position.at(0) <= ployCylFr)and(Math.sqrt(ySquared + zSquared) <= pbCylRad)) ) and not(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  puts leadShield

  if (polyCylinder) : material = "poly"
  elsif(borPolyBox) : material = "borPoly"
  elsif(cadmiumSheild) : material = "cd"
  elsif(leadSheild) : material = "pb"
  elsif(material == nil) : position = Array.new
  end

  thisEnvironment = Array.new
  thisEnvironment << position << material
  puts thisEnvironment.at(0)
  puts thisEnvironment.at(1)
end

checkPosition(40, 0, 0)

调用任何你想要的代码,但是给它* args作为参数(我很懒,可能希望将来添加更多args)然后用3个浮点数调用它,然后在逻辑中设置几何图形我会明白我的意思。

我的问题是:如何在没有一大堆嵌套if的情况下让它像它应该的那样工作(即正确地评估逻辑)? (这就是我要重拍的内容,但这是一个噩梦,阅读和内存便宜。)

4 个答案:

答案 0 :(得分:3)

你曾经多次输入“Sheild”,你可能意味着“盾牌”

在您使用它们的上下文中,您应该使用&&代替and||代替or,而!代替not。原因是orand具有如此低的优先级,导致您的赋值运算符无法按您希望的方式工作。例如,

a = b and c

评估为

(a = b) and c

这样a总是赋值b,然后在结果中真实地评估(并丢弃)c。另一方面,

a = b && c

评估为

a = (b && c)

此代码中您想要的是什么。

除此之外,我会将所有这些代码移到一个类中,这样我就可以为事物创建许多小方法:

class PositionChecker

  def initialize(*args)
    @x, @y, @z = *args
  end

  def checkPosition
    ...
  end

end

寻找机会使用方法调用替换checkPosition中的局部变量。例如,你可以将borPolyBox移动到它自己的方法中(一旦它使用的所有值都是它们自己的方法):

class PositionChecker
  ...
  def borPolyBox
    ((modX <= borPolyBoxL)||(modY < borPolyBoxL)||(modZ <= borPolyBoxL)) && !((modX >= cdBoxL)||(modY >= cdBoxL)||(modZ >= cdBoxL)) && !(Math.sqrt(ySquared + zSquared) <= polyCylRad)
  end
  ...
end

一旦你将所有这些谓词作为自己的方法,你就可以创建一个方法来确定材料,如下所示:

def material
  [
    [:polyCylinder, 'poly'],
    [:borPolyBox, 'borPoly'],
    [:cadmiumShield, 'cd'],
    [:leadShield, 'pb'],
  ].each do |method, name|
    return name if send(method)
  end
  nil
end

一个位置:

def position
  [@x, @y, @z] if material
end

沿着这条线继续前行,直到没有留下任何东西,只需要一袋小巧,专注的方法。

答案 1 :(得分:1)

将所有andor更改为&&||

之前从未见过有人使用array.at(index)代替array[index]

我还建议反对*args支持Hash参数作为一种命名参数

def test(params)
  x = params[:x] || raise("You have to provide x!")
  y = params[:y] || raise("You have to provide y!")
  z = params[:z] || raise("You have to provide z!")
  puts x, y, z
end

并使用(Ruby 1.9+语法)

调用它
test({x: 42, y: 4711, z: 93})
  

42
  4711
  93

答案 2 :(得分:0)

尝试使用&&代替and||代替or!代替not

您的问题可能是优先问题 - 请阅读this article以获取更多信息。

答案 3 :(得分:0)

查看你的代码,你设置它的方法是将四个“材料”变量作为布尔值。然后你将这些bool送入if-elsif-else块。

问题在于,如果返回true,则第一个将退出if-elsif-else块。如果这就是你保持第一个值的意思,那就是一个非常可预测的结果。