2010-11-30 45 views
1

écrire une simple simulation de Monte Carlo d'un faisceau de neutrons. Avoir des problèmes avec la logique de la géométrie (si quelque chose est dans un environnement ou un autre). Mon problème est que Ruby semble traiter les conditions de façon séquentielle et garder la première valeur à laquelle il arrive.Problème avec la logique combinée en ruby ​​

Le code ci-dessous illustre cela très bien:

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) 

appel le code que vous voulez, mais lui donnent * args comme argument (je suis paresseux et peut vouloir ajouter plus args à l'avenir) puis appelez-le avec 3 flotteurs, avec la géométrie définie dans la logique et vous verrez ce que je veux dire.

Ma question est: comment puis-je faire fonctionner comme il se doit (c'est-à-dire évaluer la logique correctement) sans un tas de si imbriqués? (Ce qui est ce que je suis sur le point de refaire, mais il est un cauchemar à lire et la mémoire ne coûte pas cher.)

+1

Pouvez-vous être plus précis sur la façon dont vous voulez évaluer la logique? Quel devrait être le code de sortie? – wdebeaum

+0

Eh bien, pour le moment tout ce que je veux regarder sont les valeurs de vérité données aux différents domaines. Cela dépend du tableau d'arguments. Mon problème est décrit dans le premier groupe de déclarations puts, l'ordre des questions de logique évaluées, quand il ne devrait pas * si j'utilise &&, || ou ou et et *, pourquoi est-ce? Je ne pense pas que ce soit le cas, mais: j'utilise l'interpréteur jEdit (que je suis sûr de regarder dans mon PATH). – morb

Répondre

0

Essayez d'utiliser && au lieu de and, || au lieu de or et ! au lieu de not.

Votre problème est probablement un précédent - lisez this article pour plus d'informations.

+0

Ou juste être incroyablement religieux sur l'utilisation des parenthèses. – philosodad

+0

il m'aide à mieux lire, et j'ai traversé toutes les permutations des opérateurs. J'ai seulement découvert aujourd'hui que vous pourriez utiliser et et ou, je suis un Ruby Noob. – morb

+0

J'ai vraiment testé && et ||, leur précédence ne semblait pas avoir d'importance. – morb

0

En regardant votre code, la façon dont vous configurez ceci est d'avoir les quatre variables "matérielles" comme des booléens. Ensuite, vous alimentez ces booléens dans un bloc if-elsif-else.

Le problème avec ceci est que le tout premier si cela renvoie vrai va sortir du bloc if-elsif-else. Si c'est ce que vous voulez dire en gardant la première valeur, il s'agit d'un résultat extrêmement prévisible.

+0

philosodad: Merci, il y a beaucoup à apprendre. Je pensais que c'était le cas. – morb

+0

Oh, non, en fait. Cela fait partie de la logique du programme, cela fonctionne à partir d'un point central testant si la position (array donnée comme arg) est dans un domaine particulier, et si autrement bloack est supposé sortir de la première vraie valeur . – morb

3

Vous avez tapé « Sheild » quelques fois où vous avez probablement voulu dire « bouclier »

Dans le contexte vous les utilisez, vous devriez utiliser && au lieu de and, || au lieu de or et ! au lieu de not. La raison en est que or et and ont une si faible préséance que vos opérateurs d'assignation ne fonctionneront pas comme vous le souhaitez. Par exemple,

a = b and c 

est évaluée comme

(a = b) and c 

tel qu'un est toujours affecté la valeur b, puis dans le résultat est truthy, c est évaluée (et mis au rebut). D'autre part,

a = b && c 

est évaluée comme

a = (b && c) 

qui est ce que vous voulez dans ce code.

Au-delà, je propose tout ce code dans une classe, afin que je puisse créer beaucoup de petites méthodes pour des choses:

class PositionChecker 

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

    def checkPosition 
    ... 
    end 

end 

Rechercher des occasions de remplacer les variables locales checkPosition avec appels de méthode.Par exemple, vous pouvez déplacer borPolyBox dans sa propre méthode (une fois toutes les valeurs qu'il utilise sont des méthodes de leur propre):

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

Une fois que vous avez tous ces prédicats comme leur propre méthode, vous pouvez créer une méthode pour déterminer le matériau, comme ceci:

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

Et un pour la position:

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

Continuer le long de cette ligne jusqu'à ce qu'il ne reste qu'un sac de Teeny, les méthodes ciblées.

+0

Merci pour ça! Tout est un objet est un concept bizarre. – morb

+0

J'ai construit autour de ce système et cela fonctionne magnifiquement, merci pour le conseil! J'utiliserai certainement ceci en traitant de la logique compliquée dans le futur. – morb

+0

@morb, De rien! Je suis content que ça a marché pour toi. –

1

Remplacez tous and et or par && et ||.

Personne n'a jamais utilisé réellement array.at(index) au lieu de array[index] auparavant.

Je recommande aussi contre *args en faveur d'un paramètre de Hash comme une sorte de paramètres nommés

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 

et l'appeler avec (syntaxe 1.9+ Ruby)

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

42
4711
93

+0

Si vous utilisez 'fetch', vous n'aurez pas besoin de' raise' si la clé n'existe pas. –

+0

Cela ne fonctionnait pas avec array [element], donc j'ai utilisé google ... – morb

+0

@Andrew Oui mais 'IndexError: key not found' n'est pas très instructif. –