Le code suivant fonctionne comme j'en ai besoin, mais c'est moche, excessif ou plusieurs autres choses. J'ai regardé des formules et tenté d'écrire quelques solutions, mais je me retrouve avec une quantité similaire de déclarations.
Existe-t-il un type de formule mathématique qui me serait utile dans ce cas ou est-ce que 16 si les énoncés sont acceptables?
Pour expliquer le code, c'est pour une sorte de jeu au tour par tour simultané. Deux joueurs ont chacun quatre boutons d'action et les résultats proviennent d'un tableau (0-3), mais les variables «un» et «deux» peuvent être rien attribué si cela aide. Le résultat est, 0 = aucune victoire, 1 = p1 gagne, 2 = p2 gagne, 3 = les deux gagnent.
public int fightMath(int one, int two) {
if(one == 0 && two == 0) { result = 0; }
else if(one == 0 && two == 1) { result = 0; }
else if(one == 0 && two == 2) { result = 1; }
else if(one == 0 && two == 3) { result = 2; }
else if(one == 1 && two == 0) { result = 0; }
else if(one == 1 && two == 1) { result = 0; }
else if(one == 1 && two == 2) { result = 2; }
else if(one == 1 && two == 3) { result = 1; }
else if(one == 2 && two == 0) { result = 2; }
else if(one == 2 && two == 1) { result = 1; }
else if(one == 2 && two == 2) { result = 3; }
else if(one == 2 && two == 3) { result = 3; }
else if(one == 3 && two == 0) { result = 1; }
else if(one == 3 && two == 1) { result = 2; }
else if(one == 3 && two == 2) { result = 3; }
else if(one == 3 && two == 3) { result = 3; }
return result;
}
if-statement
math
formula
TomFirth
la source
la source
f(a, b)
qui donne la réponse dans le cas général? Vous n'avez pas expliqué la logique du calcul, donc toutes les réponses ne sont que du rouge à lèvres sur un cochon. Je commencerais par repenser sérieusement la logique de votre programme, l'utilisation d'int
indicateurs pour les actions est très dépassée.enum
s peuvent contenir de la logique et sont descriptifs, cela vous permettrait d'écrire votre code de manière plus moderne.Réponses:
Si vous ne pouvez pas trouver une formule, vous pouvez utiliser un tableau pour un nombre aussi limité de résultats:
la source
IndexOutOfBoundsException
quand même un ou plusieurs index hors limites.i
/j
/k
pour les variables de boucle), des constantes nommées, en organisant mon code de manière lisible, etc., mais lorsque les noms de variables et de fonctions commencent à prendre plus de 20 caractères chacun je trouve que cela conduit en fait à du code moins lisible. Mon approche habituelle est d'essayer un code compréhensible mais succinct avec des commentaires ici et là pour expliquer pourquoi le code est structuré tel qu'il est (vs comment). Mettre le pourquoi dans les noms encombre tout.Étant donné que votre ensemble de données est si petit, vous pouvez tout compresser en 1 entier long et le transformer en formule
Variante plus au niveau du bit:
Cela utilise le fait que tout est un multiple de 2
L'origine de la constante magique
Que puis-je dire? Le monde a besoin de magie, parfois la possibilité de quelque chose appelle sa création.
L'essence de la fonction qui résout le problème de OP est une carte de 2 nombres (un, deux), domaine {0,1,2,3} à la plage {0,1,2,3}. Chacune des réponses a abordé la façon de mettre en œuvre cette carte.
En outre, vous pouvez voir dans un certain nombre de réponses une reformulation du problème sous la forme d'une carte de 1 base à 2 chiffres numéro 4 N (un, deux) où un est le chiffre 1, deux est le chiffre 2 et N = 4 * un + deux; N = {0,1,2, ..., 15} - seize valeurs différentes, c'est important. La sortie de la fonction est un nombre de base 4 à 1 chiffre {0,1,2,3} - 4 valeurs différentes, également importantes.
Maintenant, un nombre de base 4 à 1 chiffre peut être exprimé comme un nombre de base 2 à 2 chiffres; {0,1,2,3} = {00,01,10,11}, et ainsi chaque sortie peut être codée avec seulement 2 bits. Par dessus, il n'y a que 16 sorties différentes possibles, donc 16 * 2 = 32 bits est tout ce qui est nécessaire pour coder la carte entière; tout cela peut tenir dans 1 entier.
La constante M est un codage de la carte m où m (0) est codé en bits M [0: 1], m (1) est codé en bits M [2: 3] et m (n) est codé en bits M [n * 2: n * 2 + 1].
Il ne reste plus qu'à indexer et renvoyer la partie droite de la constante, dans ce cas, vous pouvez décaler M vers la droite 2 * N fois et prendre les 2 bits les moins significatifs, c'est-à-dire (M >> 2 * N) & 0x3. Les expressions (un << 3) et (deux << 1) multiplient simplement les choses tout en notant que 2 * x = x << 1 et 8 * x = x << 3.
la source
Je n'aime aucune des solutions présentées à l'exception des JAB. Aucun des autres ne facilite la lecture du code et la compréhension de ce qui est calculé .
Voici comment j'écrirais ce code - je ne connais que C #, pas Java, mais vous obtenez l'image:
Maintenant, il est beaucoup plus clair ce qui est calculé ici: cela souligne que nous calculons qui est touché par quelle attaque et retournons les deux résultats.
Cependant, cela pourrait être encore mieux; ce tableau booléen est quelque peu opaque. J'aime l'approche de recherche de table, mais je serais enclin à l'écrire de manière à ce que ce soit la sémantique du jeu prévue. C'est-à-dire, plutôt que "une attaque de zéro et une défense de un n'entraîne aucun coup", cherchez plutôt un moyen de faire en sorte que le code implique plus clairement "une attaque à faible coup de pied et une défense à bloc faible n'entraîne aucun coup". Faites en sorte que le code reflète la logique métier du jeu.
la source
Vous pouvez créer une matrice contenant des résultats
Lorsque vous voulez obtenir de la valeur, vous utiliserez
la source
D'autres personnes ont déjà suggéré mon idée initiale, la méthode matricielle, mais en plus de consolider les instructions if, vous pouvez éviter une partie de ce que vous avez en vous assurant que les arguments fournis sont dans la plage attendue et en utilisant des retours sur place (certains codages les normes que j'ai vues appliquent un point de sortie unique pour les fonctions, mais j'ai trouvé que les retours multiples sont très utiles pour éviter le codage des flèches et avec la prévalence d'exceptions en Java, il n'y a pas grand chose à faire appliquer strictement une telle règle de toute façon car toute exception non interceptée levée à l'intérieur de la méthode est un point de sortie possible de toute façon). L'imbrication des instructions de commutateur est une possibilité, mais pour la petite plage de valeurs que vous vérifiez ici, je trouve que les instructions doivent être plus compactes et ne devraient pas entraîner une grande différence de performances,
Cela finit par être moins lisible qu'il ne le serait autrement en raison de l'irrégularité de certaines parties du mappage d'entrée-> résultat. Je préfère le style de matrice en raison de sa simplicité et de la façon dont vous pouvez configurer la matrice pour qu'elle ait un sens visuel (bien que cela soit en partie influencé par mes souvenirs des cartes de Karnaugh):
Mise à jour: compte tenu de votre mention de blocage / frappe, voici un changement plus radical de la fonction qui utilise les types énumérés propriété / propriété d'attribut pour les entrées et le résultat et modifie également un peu le résultat pour tenir compte du blocage, ce qui devrait entraîner une plus fonction lisible.
Vous n'avez même pas besoin de changer la fonction elle-même si vous voulez ajouter des blocs / attaques de plus hauteurs, juste les énumérations; cependant, l'ajout de types de mouvements supplémentaires nécessitera probablement une modification de la fonction. De plus,
EnumSet
s peut être plus extensible que d'utiliser des énumérations supplémentaires en tant que propriétés de l'énumération principale, par exempleEnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);
et puisattacks.contains(move)
plutôt quemove.type == MoveType.ATTACK
, bien que l'utilisation deEnumSet
s soit probablement un peu plus lente que les vérifications égales directes.Dans le cas où un blocage réussi aboutit à un compteur, vous pouvez remplacer
if (one.height == two.height) return LandedHit.NEITHER;
parEn outre, le remplacement de certaines des
if
instructions par l'utilisation de l'opérateur ternaire (boolean_expression ? result_if_true : result_if_false
) pourrait rendre le code plus compact (par exemple, le code du bloc précédent deviendraitreturn one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;
), mais cela peut conduire à des oneliners plus difficiles à lire, donc je ne le ferais pas '' Je le recommande pour des branchements plus complexes.la source
one
ettwo
d'être réutilisé comme points de départ sur ma feuille de sprites. Bien qu'il ne nécessite pas beaucoup de code supplémentaire pour permettre cela.EnumMap
classe que vous pouvez utiliser pour cartographier les énumérations à vos décalages entiers (vous pouvez aussi utiliser les valeurs ordinales des membres enum directement, par exemple ,Move.ATTACK_HIGH.ordinal()
serait0
,Move.ATTACK_LOW.ordinal()
serait1
, etc., mais qui est plus fragile / moins souple que explicitement associer chaque membre à une valeur en ajoutant des valeurs d'énumération entre les valeurs existantes détruirait le décompte, ce qui ne serait pas le cas avec unEnumMap
.)attack(against)
méthode à l'Move
énumération, renvoyant HIT lorsque le mouvement est une attaque réussie, BACKFIRE lorsque le mouvement est une attaque bloquée et RIEN quand ce n'est pas une attaque. De cette façon, vous pouvez l'implémenter en général (public boolean attack(Move other) { if this.isAttack() return (other.isAttack() || other.height != this.height) ? HIT : BACKFIRE; return NOTHING; }
), et le remplacer sur des mouvements spécifiques si nécessaire (mouvements faibles que tout bloc peut bloquer, attaques qui ne se retournent jamais, etc.)Pourquoi ne pas utiliser un tableau?
Je vais recommencer depuis le début. Je vois un modèle, les valeurs vont de 0 à 3 et vous voulez attraper toutes les valeurs possibles. Voici votre table:
lorsque nous regardons ce même tableau binaire, nous voyons les résultats suivants:
Maintenant, peut-être que vous voyez déjà un modèle, mais quand je combine la valeur un et deux, je vois que vous utilisez toutes les valeurs 0000, 0001, 0010, ..... 1110 et 1111. Maintenant, combinons la valeur un et deux pour en faire un seul Entier de 4 bits.
Lorsque nous traduisons cela en valeurs décimales, nous voyons un tableau très possible de valeurs où les un et deux combinés pourraient être utilisés comme index:
Le tableau est alors
{0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3}
, où son index est simplement un et deux combinés.Je ne suis pas un programmeur Java mais vous pouvez vous débarrasser de toutes les instructions if et l'écrire simplement comme ceci:
Je ne sais pas si un décalage de bits par 2 est plus rapide que la multiplication. Mais cela pourrait valoir la peine d'essayer.
la source
Cela utilise un peu de bitmagic (vous le faites déjà en conservant deux bits d'informations (bas / haut et attaque / bloc) dans un seul entier):
Je ne l'ai pas exécuté, je l'ai seulement tapé ici, veuillez vérifier à nouveau.L'idée fonctionne sûrement. EDIT: Il est maintenant testé pour chaque entrée, fonctionne très bien.Ou devrais-je suggérer de séparer les deux bits d'information en variables distinctes? Le code basé principalement sur des opérations binaires comme ci-dessus est généralement très difficile à maintenir.
la source
return ((one ^ two) & 2) == 0 ? (one & 2) / 2 * 3 : ((one & 2) / 2 ^ ((one ^ two) & 1)) + 1;
Pour être honnête, chacun a son propre style de code. Je n'aurais pas pensé que les performances seraient trop affectées. Si vous comprenez mieux cela que d'utiliser une version de boîtier de commutation, continuez à utiliser cela.
Vous pouvez imbriquer les ifs, il y aurait donc potentiellement une légère augmentation des performances de vos dernières vérifications if, car elles n'auraient pas subi autant d'instructions if. Mais dans votre contexte d'un cours de base en Java, cela n'en bénéficiera probablement pas.
Donc, au lieu de ...
Vous feriez ...
Et reformatez-le comme vous préférez.
Cela ne rend pas le code plus beau, mais l'accélère potentiellement un peu je crois.
la source
Voyons ce que nous savons
1: vos réponses sont symétriques pour P1 (joueur un) et P2 (joueur deux). Cela a du sens pour un jeu de combat, mais c'est aussi quelque chose dont vous pouvez profiter pour améliorer votre logique.
2: 3 temps 0 temps 2 temps 1 temps 3. Les seuls cas non couverts par ces cas sont des combinaisons de 0 contre 1 et 2 contre 3. Pour le dire autrement, la table de victoire unique ressemble à ceci: 0 temps 2, 1 temps 3, 2 temps 1, 3 temps 0.
3: Si 0/1 s'affrontent, il y a égalité sans coup sûr, mais si 2/3 s'affrontent, les deux frappent
Tout d'abord, construisons une fonction à sens unique nous indiquant si nous avons gagné:
Nous pouvons ensuite utiliser cette fonction pour composer le résultat final:
Bien que cela soit sans doute plus complexe et probablement plus lent que la recherche de table proposée dans de nombreuses réponses, je pense que c'est une méthode supérieure car elle encapsule la logique de votre code et la décrit à quiconque lit votre code. Je pense que cela en fait une meilleure mise en œuvre.
(Cela fait un moment que je n'ai pas fait de Java, donc je m'excuse si la syntaxe est désactivée, j'espère qu'elle sera toujours intelligible si je me trompe un peu)
Soit dit en passant, 0-3 signifie clairement quelque chose; ce ne sont pas des valeurs arbitraires, il serait donc utile de les nommer.
la source
J'espère avoir bien compris la logique. Que diriez-vous de quelque chose comme:
Vérifier un coup haut ou un coup bas n'est pas bloqué et il en va de même pour le joueur deux.
Edit: L'algorithme n'était pas entièrement compris, "hit" attribué lors du blocage que je n'avais pas réalisé (Thx elias):
la source
Je n'ai pas d'expérience avec Java, donc il pourrait y avoir des fautes de frappe. Veuillez considérer le code comme un pseudo-code.
J'irais avec un simple interrupteur. Pour cela, vous auriez besoin d'une évaluation de numéro unique. Cependant, dans ce cas, depuis
0 <= one < 4 <= 9
et0 <= two < 4 <= 9
, nous pouvons convertir les deux entiers en un simple int en multipliantone
par 10 et en ajoutanttwo
. Ensuite, utilisez un commutateur dans le nombre résultant comme ceci:Il y a une autre méthode courte que je veux juste souligner comme un code théorique. Cependant, je ne l'utiliserais pas car il a une complexité supplémentaire que vous ne voulez normalement pas traiter. La complexité supplémentaire vient de la base 4 , car le comptage est 0, 1, 2, 3, 10, 11, 12, 13, 20, ...
Vraiment juste une note supplémentaire, au cas où je manquerais quelque chose de Java. En PHP, je ferais:
la source
Puisque vous préférez les
if
conditions imbriquées , voici une autre façon.Notez qu'il n'utilise pas le
result
membre et qu'il ne change aucun état.la source
else
chaînes mais cela n'avait fait aucune différence.else if
instructions, nous pouvons accélérer le code avecswitch
ou rechercher des tables.one==0
exécute le code, il devra alors vérifier sione==1
puis sione==2
et enfin sione==3
- S'il y avait d'autres if là-dedans, il ne ferait pas les trois dernières vérifications car il quitterait l'instruction après la première correspondance. Et oui, vous pouvez encore optimiser en utilisant une instruction switch à la place desif (one...
instructions, puis en utilisant un autre interrupteur à l'intérieur du cas de laone's
. Mais ce n'est pas ma question.Essayez-le avec un boîtier d'interrupteur. ..
Jetez un œil ici ou ici pour plus d'informations à ce sujet
Vous pouvez y ajouter plusieurs conditions (pas simultanément) et même avoir une option par défaut où aucun autre cas n'a été satisfait.
PS: Seulement si une condition doit être remplie ..
Si 2 conditions surviennent simultanément .. Je ne pense pas que l'interrupteur puisse être utilisé. Mais vous pouvez réduire votre code ici.
Instruction de commutateur Java plusieurs cas
la source
La première chose qui m'est venue à l'esprit était essentiellement la même réponse donnée par Francisco Presencia, mais quelque peu optimisée:
Vous pouvez l'optimiser davantage en faisant du dernier cas (pour 3) le cas par défaut:
L'avantage de cette méthode est qu'il est plus facile de voir quelles valeurs pour
one
ettwo
correspondent à quelles valeurs de retour que certaines des autres méthodes suggérées.la source
la source
; --unicorns
Vous pouvez utiliser un boîtier de commutation au lieu de plusieurs
if
Aussi pour mentionner que puisque vous avez deux variables, vous devez fusionner les deux variables pour les utiliser dans le commutateur
Vérifiez cette instruction de commutateur Java pour gérer deux variables?
la source
Alors que je dessine un tableau entre un / deux et le résultat, je vois un motif,
Ce qui précède réduirait au moins 3 si les déclarations. Je ne vois pas de modèle d'ensemble ni je ne peux glaner beaucoup du code donné - mais si une telle logique peut être dérivée, cela réduirait un certain nombre d'instructions if.
J'espère que cela t'aides.
la source
Un bon point serait de définir les règles comme du texte, vous pouvez alors plus facilement dériver la bonne formule. Ceci est extrait de la belle représentation de tableau de laalto:
Et nous allons ici avec quelques commentaires généraux, mais vous devez les décrire en termes de règles:
Vous pouvez bien sûr réduire cela à moins de code, mais c'est généralement une bonne idée de comprendre ce que vous codez plutôt que de trouver une solution compacte.
Une explication sur les hits p1 / p2 compliqués serait super, ça a l'air intéressant!
la source
La solution la plus courte et toujours lisible:
ou encore plus court:
Ne contient aucun chiffre "magique";) J'espère que ça aide.
la source
static int val(int i, int u){ int q = (i & 1) ^ (u & 1); return ((i >> 1) << (1 ^ q))|((u >> 1) << q); }
la source
J'aime personnellement mettre en cascade les opérateurs ternaires:
Mais dans votre cas, vous pouvez utiliser:
Ou, vous pouvez remarquer un modèle en bits:
Vous pouvez donc utiliser la magie:
la source
Voici une version assez concise, similaire à la réponse de JAB . Cela utilise une carte pour stocker ce qui triomphe des autres.
Exemple:
Tirages:
la source
static final Map<Move, List<Move>> beats = new java.util.EnumMap<>();
plutôt, il devrait être légèrement plus efficace.J'utiliserais une carte, un HashMap ou un TreeMap
Surtout si les paramètres ne sont pas sur le formulaire
0 <= X < N
Comme un ensemble d'entiers positifs aléatoires ..
Code
la source
Merci à @Joe Harper car j'ai fini par utiliser une variante de sa réponse. Pour le réduire davantage, 2 résultats pour 4 étant les mêmes, je l'ai encore réduit.
Je pourrais y revenir à un moment donné, mais s'il n'y a pas de résistance majeure causée par plusieurs
if
déclarations, je vais garder cela pour l'instant. J'examinerai la matrice de table et les solutions de déclaration de commutateur plus loin.la source
Voici une suggestion à quoi cela pourrait ressembler, mais l'utilisation d'un ints ici est toujours un peu moche:
Il serait préférable d'utiliser un type structuré pour l'entrée et la sortie. L'entrée a en fait deux champs: la position et le type (bloc ou attaque). La sortie a également deux champs: player1Wins et player2Wins. L'encodage en un seul entier rend la lecture du code plus difficile.
Malheureusement, Java n'est pas très bon pour exprimer ces types de types de données.
la source
Faites plutôt quelque chose comme ça
la source