J'ai le code suivant:
if (this->_car.getAbsoluteAngle() <= 30 || this->_car.getAbsoluteAngle() >= 330)
this->_car.edir = Car::EDirection::RIGHT;
else if (this->_car.getAbsoluteAngle() > 30 && this->_car.getAbsoluteAngle() <= 60)
this->_car.edir = Car::EDirection::UP_RIGHT;
else if (this->_car.getAbsoluteAngle() > 60 && this->_car.getAbsoluteAngle() <= 120)
this->_car.edir = Car::EDirection::UP;
else if (this->_car.getAbsoluteAngle() > 120 && this->_car.getAbsoluteAngle() <= 150)
this->_car.edir = Car::EDirection::UP_LEFT;
else if (this->_car.getAbsoluteAngle() > 150 && this->_car.getAbsoluteAngle() <= 210)
this->_car.edir = Car::EDirection::LEFT;
else if (this->_car.getAbsoluteAngle() > 210 && this->_car.getAbsoluteAngle() <= 240)
this->_car.edir = Car::EDirection::DOWN_LEFT;
else if (this->_car.getAbsoluteAngle() > 240 && this->_car.getAbsoluteAngle() <= 300)
this->_car.edir = Car::EDirection::DOWN;
else if (this->_car.getAbsoluteAngle() > 300 && this->_car.getAbsoluteAngle() <= 330)
this->_car.edir = Car::EDirection::DOWN_RIGHT;
Je veux éviter la if
chaîne s; c'est vraiment moche. Y a-t-il une autre façon, peut-être plus propre, d'écrire cela?
c++
if-statement
Oraekia
la source
la source
this->_car.getAbsoluteAngle()
fois avant toute la cascade.this
(this->
) n'est pas nécessaire et ne fait rien de bon pour la lisibilité.>
tests; ils ne sont pas nécessaires, car chacun d'eux a déjà été testé (dans la direction opposée) dans l'if
instruction précédente .else if
.Réponses:
Voilà comment je le ferais. (Selon mon commentaire précédent).
la source
q = a/b
etr = a%b
alorsq * b + r
doivent être égauxa
. Il est donc légal en C99 qu'un reste soit négatif. BorgLeader, vous pouvez résoudre le problème avec(((angle % 360) + 360) % 360) / 30
.GetDirectionForAngle
c'est ce que je propose en remplacement de la cascade if / else, ils sont tous les deux O (1) ...Vous pouvez utiliser
map::lower_bound
et stocker la limite supérieure de chaque angle dans une carte.Exemple de travail ci-dessous:
la source
table[angle%360/30]
réponses parce qu'elle est bon marché et sans succursale. Beaucoup moins cher qu'une boucle de recherche arborescente, si cela compile en asm qui est similaire à la source. (std::unordered_map
est généralement une table de hachage, maisstd::map
est généralement un arbre binaire rouge-noir. La réponse acceptée estangle%360 / 30
utilisée comme une fonction de hachage parfaite pour les angles (après avoir répliqué quelques entrées, et la réponse de Bijay évite même cela avec un décalage)).lower_bound
sur un tableau trié. Ce serait beaucoup plus efficace qu'unmap
.this->_car.getAbsoluteAngle()
avec une variable tmp, et en supprimant la comparaison redondante de chacune desif()
clauses de l'OP (vérifier quelque chose qui aurait déjà correspondu le précédent if ()). Ou utilisez la suggestion de tableau trié de @ wilx.Créez un tableau dont chaque élément est associé à un bloc de 30 degrés:
Ensuite, vous pouvez indexer le tableau avec l'angle / 30:
Aucune comparaison ou branchement requis.
Le résultat est cependant légèrement différent de l'original. Les valeurs sur les bordures, c'est-à-dire 30, 60, 120, etc. sont placées dans la catégorie suivante. Par exemple, dans le code d'origine, les valeurs valides pour
UP_RIGHT
sont de 31 à 60. Le code ci-dessus affecte 30 à 59 àUP_RIGHT
.Nous pouvons contourner cela en soustrayant 1 de l'angle:
Cela nous donne maintenant
RIGHT
pour 30,UP_RIGHT
pour 60, etc.Dans le cas de 0, l'expression devient
(-1 % 360) / 30
. Ceci est valable parce que-1 % 360 == -1
et-1 / 30 == 0
, donc nous obtenons toujours un index de 0.La section 5.6 de la norme C ++ confirme ce comportement:
ÉDITER:
De nombreuses questions ont été soulevées concernant la lisibilité et la maintenabilité d'une construction comme celle-ci. La réponse donnée par motoDrizzt est un bon exemple de simplification de la construction originale qui est plus maintenable et n'est pas aussi «moche».
En développant sa réponse, voici un autre exemple utilisant l'opérateur ternaire. Étant donné que chaque cas dans l'article d'origine est assigné à la même variable, l'utilisation de cet opérateur peut aider à améliorer encore la lisibilité.
la source
Ce code n'est pas moche, il est simple, pratique, lisible et facile à comprendre. Il sera isolé dans sa propre méthode, donc personne n'aura à s'en occuper dans la vie de tous les jours. Et juste au cas où quelqu'un devrait le vérifier - peut-être parce qu'il débogue votre application pour un problème ailleurs - c'est tellement facile qu'il lui faudra deux secondes pour comprendre le code et ce qu'il fait.
Si je faisais un tel débogage, je serais heureux de ne pas avoir à passer cinq minutes à essayer de comprendre ce que fait votre fonction. À cet égard, toutes les autres fonctions échouent complètement, car elles changent une routine simple, sans bogues et sans bogues, dans un désordre compliqué que les personnes lors du débogage seront obligées d'analyser et de tester en profondeur. En tant que chef de projet moi-même, je serais fortement contrarié par un développeur prenant une tâche simple et au lieu de l'implémenter de manière simple et inoffensive, je perdrais du temps à l'implémenter de manière trop compliquée. Pensez simplement à tout le temps que vous avez perdu à y penser, puis à vous adresser à SO demander, et tout cela dans le seul souci de détériorer la maintenance et la lisibilité de la chose.
Cela dit, il y a une erreur courante dans votre code qui le rend beaucoup moins lisible, et quelques améliorations que vous pouvez faire assez facilement:
Mettez ceci dans une méthode, affectez la valeur renvoyée à l'objet, réduisez la méthode et oubliez-la pour le reste de l'éternité.
PS il y a un autre bogue au-dessus du seuil 330, mais je ne sais pas comment vous voulez le traiter, donc je ne l'ai pas corrigé du tout.
Mise à jour ultérieure
Selon le commentaire, vous pouvez même vous débarrasser de l'autre, voire pas du tout:
Je ne l'ai pas fait parce que j'estime qu'à un certain moment, cela devient juste une question de préférences personnelles, et la portée de ma réponse était (et est) de donner une perspective différente à votre inquiétude concernant la "laideur du code". Quoi qu'il en soit, comme je l'ai dit, quelqu'un l'a souligné dans les commentaires et je pense qu'il est logique de le montrer.
la source
else if
,if
c'est suffisant.else if
. Je trouve utile de pouvoir jeter un coup d'œil sur un bloc de code et de voir qu'il s'agit d'un arbre de décision plutôt que d'un groupe d'instructions non liées. Oui,else
oubreak
ne sont pas nécessaires pour le compilateur après areturn
, mais ils sont utiles pour l'humain qui regarde le code.elseif
/ séparéelsif
, soit vous utilisez techniquement un bloc à une instruction qui commenceif
, comme ici. Exemple rapide de ce à quoi je pense que vous pensez, et à quoi je pense: gist.github.com/IMSoP/90bc1e9e2c56d8314413d7347e76532aelse
raison pour laquelle vous faites cela, c'est un mauvais guide de style qui ne se reconnaît paselse if
comme une déclaration distincte. J'utiliserais toujours des accolades, mais je n'écrirais jamais de code comme ça, comme je l'ai montré dans mon essence.En pseudocode:
Nous avons donc
0-60
,60-90
,90-150
, ... comme les catégories. Dans chaque quadrant de 90 degrés, une partie en a 60, une partie en a 30. Alors, maintenant:Utilisez l'index dans un tableau contenant les énumérations dans l'ordre approprié.
la source
la source
Ignorant votre premier
if
qui est un peu un cas particulier, les autres suivent tous exactement le même schéma: un min, un max et une direction; pseudo-code:Faire de ce vrai C ++ pourrait ressembler à:
Maintenant, plutôt que d'écrire un tas de
if
s, parcourez simplement vos différentes possibilités:(
throw
Une exception plutôtreturn
qu'ingNONE
est une autre option).Ce que vous appelleriez alors:
Cette technique est connue sous le nom de programmation basée sur les données . En plus de vous débarrasser d'un tas de
if
s, cela vous permettrait d'ajouter facilement plus de directions (par exemple, NNW) ou de réduire le nombre (gauche, droite, haut, bas) sans retravailler d'autres codes.(Le traitement de votre premier cas particulier est laissé comme "un exercice pour le lecteur" :-))
la source
if(angle <= angleRange.max)
+1 pour l'utilisation de fonctionnalités C ++ 11 telles queenum class
.Bien que les variantes proposées basées sur une table de recherche
angle / 30
soient probablement préférables, voici une alternative qui utilise une recherche binaire codée en dur pour minimiser le nombre de comparaisons.la source
Si vous voulez vraiment éviter la duplication, vous pouvez l'exprimer sous forme de formule mathématique.
Tout d'abord, supposons que nous utilisons Enum de @ Geek
Nous pouvons maintenant calculer l'énumération en utilisant des mathématiques entières (sans avoir besoin de tableaux).
Comme le souligne @motoDrizzt, un code concis n'est pas nécessairement un code lisible. Cela présente le petit avantage de l'exprimer sous forme de mathématiques, ce qui explique clairement que certaines directions couvrent un arc plus large. Si vous voulez aller dans cette direction, vous pouvez ajouter des assertions pour aider à comprendre le code.
Après avoir ajouté les assertions, vous avez ajouté la duplication, mais la duplication dans les assertions n'est pas si grave. Si vous avez une affirmation incohérente, vous le saurez assez tôt. Les assertions peuvent être compilées hors de la version finale afin de ne pas gonfler l'exécutable que vous distribuez. Néanmoins, cette approche est probablement la plus applicable si vous souhaitez optimiser le code plutôt que simplement le rendre moins laid.
la source
Je suis en retard à la fête, mais nous pourrions utiliser des indicateurs d'énumération et des vérifications de plage pour faire quelque chose de soigné.
la vérification (pseudo-code), en supposant que l'angle est absolu (entre 0 et 360):
la source