Çok fazla 'if' ifadesi var mı?


263

Aşağıdaki kod nasıl ihtiyacım var çalışır, ama bu çirkin, aşırı veya başka şeyler. Formüllere baktım ve birkaç çözüm yazmaya çalıştım, ancak benzer miktarda ifadeyle sonuçlandım.

Bu örnekte bana fayda sağlayacak bir tür matematik formülü var mı yoksa ifadeler kabul edilebilirse 16 mı?

Kodu açıklamak için, bir tür eşzamanlı dönüş tabanlı oyun içindir .. iki oyuncunun her biri dört eylem düğmesi vardır ve sonuçlar bir diziden (0-3) gelir, ancak 'one' ve 'two' değişkenleri olabilir bu yardımcı olursa bir şey atar. Sonuç, 0 = ne kazanırsa, 1 = p1 kazanır, 2 = p2 kazanır, 3 = her ikisi de kazanır.

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;
}


9
Kuşkusuz burada kaba zorlama yerine genelleştirilebilen bir mantık var mı? Elbette f(a, b)genel durumda cevabı veren bazı fonksiyonlar var mı? Hesaplamanın mantığını açıklamadınız, bu nedenle tüm cevaplar bir domuzun rujudur. Program mantığını ciddi bir şekilde yeniden düşünerek başlayacağım, inteylemler için bayraklar kullanmak çok eski. enums mantık içerebilir ve açıklayıcıdır; bu, kodunuzu daha modern bir şekilde yazmanıza olanak tanır.
Örümcek Boris

Yukarıda bağlantılı alternatif sorusunda verilen @Steve Benett'in cevaplarını okuduktan sonra, aslında bir veritabanı ile aynı olduğu için bunun doğru bir formül cevabı olmadığını varsayabilirim. Orijinal soruda basit bir oyun (savaşçı) yaptığımı açıklamaya çalıştım ve kullanıcıların 4 düğme seçeneği var: blockHigh (0), blockLow (1), attackHigh (2) ve attackLow (3). Bu sayılar gerekene kadar bir dizide tutulur. Daha sonra sonuç vermek için playerOne'un playerTwos'a karşı seçimlerini çağıran 'fightMath ()' fonksiyonu tarafından kullanılırlar. Gerçek çarpışma tespiti yok.
TomFirth

9
Cevabınız varsa, lütfen bu şekilde gönderin. Özellikle kod söz konusu olduğunda yorumlardaki genişletilmiş tartışmayı takip etmek zordur. Bu sorunun Kod İncelemesine taşınması gerekip gerekmediği hakkında konuşmak istiyorsanız, bununla ilgili bir Meta tartışması var.
George Stocker

1
"Veritabanı ile aynı" ile ne demek istiyorsun? Bu değerler veritabanındaysa, onları oradan çekin. Aksi takdirde, gerçekten bu karmaşıksa, her şeyden sonra olduğu gibi bırakıp insanların ne olduğunu anlaması için iş mantığı yorumları eklerdim. Benim için uzun ve açık daha iyidir - gelecekte biri neler olup bittiğini anlayabilir. Bir haritaya koyarsanız veya 8 satır kod kaydetmeye çalışırsanız, üst kısım gerçekten küçüktür ve küçülme daha büyüktür: bir gün kodunuzu okuması gereken biri için daha fazla kafa karıştırıcı hale getirirsiniz.
skaz

Yanıtlar:


600

Bir formül bulamazsanız, sınırlı sayıda sonuç için bir tablo kullanabilirsiniz:

final int[][] result = new int[][] {
  { 0, 0, 1, 2 },
  { 0, 0, 2, 1 },
  { 2, 1, 3, 3 },
  { 1, 2, 3, 3 }
};
return result[one][two];

7
Bu çözümü daha önce görmediğim için ilginç. Geri dönüş sonucunu anladığımdan emin değilim ama bunu test etmekten keyif alacaksınız.
TomFirth

4
İddiaya ihtiyacınız yok, IndexOutOfBoundsExceptionbir veya daha fazla endeks sınırların dışındaysa Java yine de atacaktır .
JAB

43
@JoeHarper Okuması kolay bir şey istiyorsanız, ilk etapta sihirli sayılar kullanmayacaksınız ve haritalamayı açıklayan bir yorumunuz olacak. Olduğu gibi, bu sürümü orijinaline tercih ederim, ancak uzun vadede sürdürülebilecek bir şey için numaralandırılmış türleri veya en azından adlandırılmış sabitleri içeren bir yaklaşım kullanacağım.
JAB

13
@JoeHarper "Teorik olarak" bir şeydir, "pratikte" başka bir şeydir. Elbette , sabitleri adlandırılmış, kodumu okunabilir bir şekilde düzenleyerek, vb. Tanımlayıcı adlandırma ( i/ j/ kkonvansiyonu hariç) kullanmaya çalışıyorum , ancak değişken ve işlev adları 20'den fazla karakter almaya başladığında her buldum aslında daha az okunabilir kod yol açar. Her zamanki yaklaşımım, kodun neden olduğu gibi yapılandırıldığını (nasıl ve nasıl) açıklamak için burada ve orada anlaşılır ama kısa ve özlü kodlar denemektir . Neden isimleri koymak sadece her şeyi kesiyor.
JAB

13
Bu çözüm için bu çözümü seviyorum, çünkü sonuçlar aslında bir sonuç matrisi tarafından dikte ediliyor.
çalışılıyor

201

Veri kümeniz çok küçük olduğundan, her şeyi 1 uzun tamsayıya sıkıştırabilir ve bir formüle dönüştürebilirsiniz.

public int fightMath(int one,int two)
{
   return (int)(0xF9F66090L >> (2*(one*4 + two)))%4;
}

Daha bitsel varyant:

Bu, her şeyin 2'nin katları olduğu gerçeğinden yararlanır

public int fightMath(int one,int two)
{
   return (0xF9F66090 >> ((one << 3) | (two << 1))) & 0x3;
}

Büyü Sabiti'nin Kökeni

Ne söyleyebilirim? Dünyanın sihire ihtiyacı vardır, bazen bir şeyin yaratılması olasılığı çağrılır.

OP'nin problemini çözen fonksiyonun özü, 2 sayıdan (bir, iki), alan {0,1,2,3} ile {0,1,2,3} aralığına bir haritadır. Yanıtların her biri bu haritanın nasıl uygulanacağına yaklaştı.

Ayrıca, cevapların bir kısmında sorunun bir yeniden ifade edilmesini, 1 basamaklı 1, iki basamak 2 ve N = 4 * bir olan 1 2 basamaklı 4 numaralı N (bir, iki) haritası olarak görebilirsiniz. + iki; N = {0,1,2, ..., 15} - on altı farklı değer, bu önemli. İşlevin çıktısı 1 basamaklı bir temel 4 sayısı {0,1,2,3} - 4 farklı değerdir, ayrıca önemlidir.

Şimdi, 1 basamaklı bir taban 4 sayısı 2 basamaklı bir taban 2 sayısı olarak ifade edilebilir; {0,1,2,3} = {00,01,10,11} ve böylece her çıkış yalnızca 2 bitle kodlanabilir. Yukarıdan, sadece 16 farklı çıkış mümkündür, bu nedenle tüm haritayı kodlamak için gerekli olan 16 * 2 = 32 bit yeterlidir; bu 1 tamsayıya sığabilir.

M sabiti, m (0) 'nın M [0: 1] bitlerinde kodlandığı, m (1) M [2: 3] bitlerinde kodlandığı ve m (n) bit olarak kodlandığı m haritasının bir kodlamasıdır. M [n * 2: n * 2 + 1].

Geriye kalan tek şey sabitlemenin sağ kısmını indekslemek ve döndürmektir, bu durumda M sağını 2 * N kez kaydırabilir ve en az önemli 2 biti (M >> 2 * N) & 0x3 alabilirsiniz. (Bir << 3) ve (iki << 1) ifadeleri, 2 * x = x << 1 ve 8 * x = x << 3 olduğuna dikkat çekerek bir şeyleri çoğaltır.


79
akıllı, ancak kodu okuyan hiç kimse kodu anlama şansına sahip olmayacak.
Aran Mulholland

106
Bunun son derece kötü bir uygulama olduğunu düşünüyorum. Bunu yazar dışında başka kimse anlamayacak. Bir parça koda bakmak ve çabucak anlamak istiyorsunuz. Ama bu sadece zaman kaybı.
Balázs Németh

14
Bu konuda @ BalázsMáriaNémeth ile beraberim. Çok etkileyici olmasına rağmen, şiddetli psikopatlar için kod yazmalısınız!
OrhanC1

90
Tüm iniş çıkışçılar bunun iğrenç bir kod kokusu olduğunu düşünüyor. Tüm yükselenler aynı şeyi düşünür, ancak arkasındaki zekâya hayran kalırlar. +1 (Bu kodu asla kullanmayın.)
usr

4
Sadece kod yazma ne güzel bir örnek !
lealand

98

JAB'lar dışında sunulan çözümlerin hiçbirini sevmiyorum. Diğer hiçbiri kodu okumayı ve neyin hesaplandığını anlamayı kolaylaştırmaz .

İşte bu kodu yazmak nasıl - Java değil, sadece C # biliyorum, ama resim olsun:

const bool t = true;
const bool f = false;
static readonly bool[,] attackResult = {
    { f, f, t, f }, 
    { f, f, f, t },
    { f, t, t, t },
    { t, f, t, t }
};
[Flags] enum HitResult 
{ 
    Neither = 0,
    PlayerOne = 1,
    PlayerTwo = 2,
    Both = PlayerOne | PlayerTwo
}
static HitResult ResolveAttack(int one, int two)
{
    return 
        (attackResult[one, two] ? HitResult.PlayerOne : HitResult.Neither) | 
        (attackResult[two, one] ? HitResult.PlayerTwo : HitResult.Neither);
}    

Şimdi burada neyin hesaplandığı çok daha açık: Bu, kimin hangi saldırıdan vurulduğunu hesapladığımızı ve her iki sonucu da geri verdiğimizi vurgulamaktadır.

Ancak bu daha da iyi olabilir; Boole dizisi biraz opak. Tablo arama yaklaşımını seviyorum, ancak amaçlanan oyun semantiğinin ne olduğunu netleştirecek şekilde yazmaya eğilimliydim. Yani "sıfır atak ve isabetsiz bir sonucun savunulması" yerine, kodu daha açık bir şekilde "düşük vuruş saldırısı ve düşük blok savunması isabetsiz sonuç" anlamına gelecek şekilde bulmanın bir yolunu bul. Kodun oyunun iş mantığını yansıtmasını sağlayın.


66
Saçmalık. En hafif tecrübeli programlar burada verilen tavsiyeleri takdir edebilecek ve kodlama stilini kendi diline uygulayabilecektir. Soru, ifs dizesinden nasıl kaçınılacağıydı. Bu nasıl olduğunu gösterir.
GreenAsJade

6
@ user3414693: Bunun bir Java sorusu olduğunun farkındayım. Cevabı dikkatlice okursanız bu netleşir. Cevabımın yanlış olduğuna inanıyorsanız, daha iyi sevdiğiniz cevabı yazmanızı tavsiye ederim.
Eric Lippert

1
@EricLippert Ben de JAB'ın çözümünü seviyorum. IMHO, C # 'daki enum tipi arzulanan çok şey bırakıyor. Diğer özelliklerin yaptığı başarı felsefesinin çukuruna uymuyor. Örneğin stackoverflow.com/a/847353/92414 c # ekibinin daha iyi tasarlanmış yeni bir numaralandırma türü oluşturmak için herhangi bir planı var mı?
SolutionYogi

@SolutionYogi: İyi tarihsel nedenlerden ötürü olmalarına rağmen C # 'daki sıralamaları sevmiyorum. (Çoğunlukla mevcut COM numaralarıyla uyumluluk için.) C # 6'da numaralandırmalar için yeni dişli eklemenin herhangi bir planının farkında değilim.
Eric Lippert

3
@SList no, yorumlar çalışmaz. OP tam olarak ne yapılması gerektiğini yaptı; yorumları açık kodu dönüştür. Bkz. Örneğin Steve McConnell Code Complete stevemcconnell.com/cccntnt.htm
djechlin

87

Sonuç içeren bir matris oluşturabilirsiniz

int[][] results = {{0, 0, 1, 2}, {0, 0, 2, 1},{2, 1, 3, 3},{2, 1, 3, 3}};

Değer almak istediğinizde kullanacaksınız

public int fightMath(int one, int two) {
  return this.results[one][two]; 
}

69

Diğer insanlar ilk fikrimi, matris yöntemini zaten önerdiler, ancak if ifadelerini birleştirmeye ek olarak, sağlanan argümanların beklenen aralıkta olduğundan ve yerinde dönüşler (bazı kodlama) kullanarak sahip olduğunuz şeylerden bazılarını önleyebilirsiniz. Standartlar işlevler için bir çıkış noktası uyguladığını gördüm, ancak ok kodlamasından kaçınmak için birden fazla dönüşün çok yararlı olduğunu gördüm ve Java'daki istisnaların yaygınlığıyla, böyle bir kuralın kesinlikle uygulanmasının pek bir anlamı yok çünkü yönteme atılan yakalanmamış istisnalar olası bir çıkış noktasıdır). Anahtar ifadelerini iç içe yerleştirme bir olasılıktır, ancak burada kontrol ettiğiniz küçük değer aralığı için ifadelerin daha kompakt olup olmadığını ve performans farkının çoğuyla sonuçlanmasının olası olmadığını,

public int fightMath(int one, int two) {
    if (one > 3 || one < 0 || two > 3 || two < 0) {
        throw new IllegalArgumentException("Result is undefined for arguments outside the range [0, 3]");
    }

    if (one <= 1) {
        if (two <= 1) return 0;
        if (two - one == 2) return 1;
        return 2; // two can only be 3 here, no need for an explicit conditional
    }

    // one >= 2
    if (two >= 2) return 3;
    if (two == 1) return 1;
    return 2; // two can only be 0 here
}

Bu, aksi takdirde giriş-> sonuç eşlemesinin parçalarının düzensizliğinden kaynaklanabileceğinden daha az okunabilir hale gelir. Basitliği ve matrisi görsel olarak mantıklı hale getirmek için nasıl ayarlayabileceğinizi yerine matris stilini tercih ediyorum (bu kısmen Karnaugh haritalarındaki anılarımdan etkileniyor):

int[][] results = {{0, 0, 1, 2},
                   {0, 0, 2, 1},
                   {2, 1, 3, 3},
                   {2, 1, 3, 3}};

Güncelleme: Engelleme / isabetten bahsettiğinizde, girişler ve sonuç için doğrulanmış / öznitelik tutma numaralandırılmış türlerini kullanan ve ayrıca engelleme için sonucu biraz değiştirecek şekilde işlevde daha radikal bir değişiklik. okunabilir işlev.

enum MoveType {
    ATTACK,
    BLOCK;
}

enum MoveHeight {
    HIGH,
    LOW;
}

enum Move {
    // Enum members can have properties/attributes/data members of their own
    ATTACK_HIGH(MoveType.ATTACK, MoveHeight.HIGH),
    ATTACK_LOW(MoveType.ATTACK, MoveHeight.LOW),
    BLOCK_HIGH(MoveType.BLOCK, MoveHeight.HIGH),
    BLOCK_LOW(MoveType.BLOCK, MoveHeight.LOW);

    public final MoveType type;
    public final MoveHeight height;

    private Move(MoveType type, MoveHeight height) {
        this.type = type;
        this.height = height;
    }

    /** Makes the attack checks later on simpler. */
    public boolean isAttack() {
        return this.type == MoveType.ATTACK;
    }
}

enum LandedHit {
    NEITHER,
    PLAYER_ONE,
    PLAYER_TWO,
    BOTH;
}

LandedHit fightMath(Move one, Move two) {
    // One is an attack, the other is a block
    if (one.type != two.type) {
        // attack at some height gets blocked by block at same height
        if (one.height == two.height) return LandedHit.NEITHER;

        // Either player 1 attacked or player 2 attacked; whoever did
        // lands a hit
        if (one.isAttack()) return LandedHit.PLAYER_ONE;
        return LandedHit.PLAYER_TWO;
    }

    // both attack
    if (one.isAttack()) return LandedHit.BOTH;

    // both block
    return LandedHit.NEITHER;
}

Daha yükseklikte bloklar / saldırılar eklemek istiyorsanız, yalnızca numaralandırmalar işlevinin kendisini değiştirmek zorunda bile değilsiniz; Ancak, ek hareket türleri eklemek muhtemelen işlevin değiştirilmesini gerektirecektir. Ayrıca, EnumSets enumları ana enumun özellikleri olarak kullanmaktan daha uzatılabilir, örneğin EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);ve daha attacks.contains(move)ziyade move.type == MoveType.ATTACK, EnumSets'yi kullanmak muhtemelen doğrudan eşit denetimlerden biraz daha yavaş olacaktır.


Başarılı bir bloğun bir sayaçla sonuçlanması durumunda if (one.height == two.height) return LandedHit.NEITHER;,

if (one.height == two.height) {
    // Successful block results in a counter against the attacker
    if (one.isAttack()) return LandedHit.PLAYER_TWO;
    return LandedHit.PLAYER_ONE;
}

Ayrıca, bazı ififadelerin üçlü operatör ( boolean_expression ? result_if_true : result_if_false) kullanımı ile değiştirilmesi , kodu daha kompakt hale getirebilir (örneğin, önceki bloktaki kod haline gelir return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;), ancak bu, daha zor okunan onelinerlere yol açabilir. t Daha karmaşık dallanmalar için tavsiye etmem.


Kesinlikle bu işe bakacağız ama benim geçerli kod bana ait int değerini kullanmanıza olanak oneve twobenim spritesheet üzerinde başlangıç noktaları olarak yeniden kullanılmak üzere. Buna izin vermek için fazladan kod gerektirmemesine rağmen.
TomFirth

2
@ TomFirth84 bir var EnumMapsen (siz de örneğin doğrudan enum üyelerinin sıralı değerlerini kullanabilirsiniz sizin tamsayı sapmalarına Çeteleler eşlemek için kullanabileceği sınıf Move.ATTACK_HIGH.ordinal()olurdu 0, Move.ATTACK_LOW.ordinal()olurdu 1vb, ancak açıkça daha o en fazla kırılgan / az esnek her bir üyeyi mevcut olanlar arasında enum değerleri ekleyerek bir değerle ilişkilendirmek sayımı atar, ki bu durum böyle olmaz EnumMap.)
JAB

7
Bu en okunabilir çözümdür, çünkü kodu kodu okuyan kişi için anlamlı bir şeye dönüştürür.
David Stanley

En azından numaralandırma kullanan kodunuz yanlış. OP'deki if ifadelerine başarılı bir blok takılması saldırganın isabetine yol açar. Ancak anlamlı kod için +1.
Mart'ta Taemyr

2
Enum'a bir attack(against)yöntem bile ekleyebilir Move, hareket başarılı bir saldırı olduğunda HIT, hareket engellenen bir saldırı olduğunda BACKFIRE ve bir saldırı olmadığında NOTH döndürebilirsiniz. Bu şekilde genel olarak ( public boolean attack(Move other) { if this.isAttack() return (other.isAttack() || other.height != this.height) ? HIT : BACKFIRE; return NOTHING; }) uygulayabilir ve gerektiğinde belirli hareketlerde geçersiz kılabilirsiniz (herhangi bir bloğun engelleyebileceği zayıf hareketler, asla geri tepmeyen saldırılar vb.)
yeniden yazılmıştır

50

Neden bir dizi kullanmıyorsunuz?

En baştan başlayacağım. Bir desen görüyorum, değerler 0'dan 3'e gidiyor ve olası tüm değerleri yakalamak istiyorsunuz. İşte masanız:

0 & 0 = 0
0 & 1 = 0
0 & 2 = 1
0 & 3 = 2
1 & 0 = 0
1 & 1 = 0
1 & 2 = 2
1 & 3 = 1
2 & 0 = 2
2 & 1 = 1
2 & 2 = 3
2 & 3 = 3
3 & 0 = 2
3 & 1 = 1
3 & 2 = 3
3 & 3 = 3

aynı tablo ikili dosyasına baktığımızda şu sonuçları görüyoruz:

00 & 00 = 00
00 & 01 = 00
00 & 10 = 01
00 & 11 = 10
01 & 00 = 00
01 & 01 = 00
01 & 10 = 10
01 & 11 = 01
10 & 00 = 10
10 & 01 = 01
10 & 10 = 11
10 & 11 = 11
11 & 00 = 10
11 & 01 = 01
11 & 10 = 11
11 & 11 = 11

Şimdi belki zaten bir desen görüyorsunuz, ancak bir ve iki değeri birleştirdiğimde, tüm değerleri 0000, 0001, 0010, ..... 1110 ve 1111'i kullandığınızı görüyorum. Şimdi tek bir değer oluşturmak için bir ve iki değerini birleştirelim. 4 bit tam sayı.

0000 = 00
0001 = 00
0010 = 01
0011 = 10
0100 = 00
0101 = 00
0110 = 10
0111 = 01
1000 = 10
1001 = 01
1010 = 11
1011 = 11
1100 = 10
1101 = 01
1110 = 11
1111 = 11

Bunu tekrar ondalık değerlere çevirdiğimizde, bir ve iki birleştirmenin dizin olarak kullanılabileceği çok olası bir değer dizisi görüyoruz:

0 = 0
1 = 0
2 = 1
3 = 2
4 = 0
5 = 0
6 = 2
7 = 1
8 = 2
9 = 1
10 = 3
11 = 3
12 = 2
13 = 1
14 = 3
15 = 3

Bu durumda dizi, dizinin {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3}basitçe bir ve iki birleşimidir.

Ben bir Java programcısı değilim ama tüm if ifadelerden kurtulabilir ve sadece böyle bir şey olarak yazabilirsiniz:

int[] myIntArray = {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3};
result = myIntArray[one * 4 + two]; 

Bitshift'in 2 ile çarpma işleminden daha hızlı olup olmadığını bilmiyorum. Ama denemeye değer olabilir.


2
2 bitlik bir bit kaydırma neredeyse 4'ün çarpılmasından neredeyse daha hızlıdır. Açıkçası, bana göre, geçiş daha okunaklı.
Cruncher

Yaklaşımını seviyorum! Bir 4x4 matrisi esasen 16 elemanlı bir diziye yassılaştırır.
Cameron Tinker

6
Günümüzde, eğer yanılmıyorsam, derleyici şüphesiz ki iki güçle çarptığınızı fark edecek ve buna göre optimize edecektir. Yani sizin için programcı, bit kaydırma ve çarpma tam olarak aynı performansa sahip olmalıdır.
Tanner Swett

24

Bu, biraz bitmagic kullanır (bunu tek bir tamsayıda iki bit bilgi (düşük / yüksek & saldırı / blok) tutarak zaten yapıyorsunuz):

Ben çalıştırmadım, sadece buraya yazdım, lütfen kontrol edin. Fikir kesinlikle işe yarıyor. EDIT: Şimdi her giriş için test edilmiştir, iyi çalışıyor.

public int fightMath(int one, int two) {
    if(one<2 && two<2){ //both players blocking
        return 0; // nobody hits
    }else if(one>1 && two>1){ //both players attacking
        return 3; // both hit
    }else{ // some of them attack, other one blocks
        int different_height = (one ^ two) & 1; // is 0 if they are both going for the same height - i.e. blocker wins, and 1 if height is different, thus attacker wins
        int attacker = one>1?1:0; // is 1 if one is the attacker, two is the blocker, and 0 if one is the blocker, two is the attacker
        return (attacker ^ different_height) + 1;
    }
}

Yoksa iki bilgi parçasını ayrı değişkenlere ayırmayı mı önermeliyim? Yukarıdaki gibi çoğunlukla bit işlemlerine dayanan kodun bakımı genellikle gerçekten zordur.


2
Bu çözüme katılıyorum, ana soru hakkındaki yorumumda aklımdakilere çok benziyor. Bunu, örneğin gelecekte orta saldırı eklemeyi kolaylaştıracak ayrı değişkenlere bölmeyi tercih ederim.
Yoh

2
Test ettikten sonra yukarıdaki koddaki bazı hataları düzelttim, şimdi iyi çalışıyor. Bit manipülatörün yolunda daha da ileri giderek, tek cevaplı bir çözüm de buldum, ki bu hala diğer cevaplardaki bitmask kadar mistik değil, ama yine de zihninizi vidalayacak kadar zor:return ((one ^ two) & 2) == 0 ? (one & 2) / 2 * 3 : ((one & 2) / 2 ^ ((one ^ two) & 1)) + 1;
elias

1
Okuduğu herhangi bir yeni programcı, tüm bu sihirli sayıların arkasında gerçekleşen büyüyü anlayacağından, bu en iyi cevaptır.
14'te bezmax

20

Dürüst olmak gerekirse, herkesin kendi kod stili vardır. Performansın çok fazla etkileneceğini düşünmezdim. Bunu bir anahtar kasa sürümü kullanmaktan daha iyi anlıyorsanız, kullanmaya devam edin.

If'leri iç içe yerleştirebilirsiniz, bu nedenle potansiyel olarak, eğer if ifadeleri kadar geçmeyeceği kadar kontrol ederse son performansınız için hafif bir performans artışı olacaktır. Ancak, temel bir java kursu bağlamında muhtemelen faydası olmayacaktır.

else if(one == 3 && two == 3) { result = 3; }

Yani, yerine ...

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; }

Sen yapardın ...

if(one == 0) 
{ 
    if(two == 0) { result = 0; }
    else if(two == 1) { result = 0; }
    else if(two == 2) { result = 1; }
    else if(two == 3) { result = 2; }
}

Ve sadece istediğiniz gibi yeniden biçimlendirin.

Bu kod daha iyi görünmüyor, ama muhtemelen biraz hızlandırır inanıyorum.


3
Gerçekten iyi bir uygulama olup olmadığını bilmiyorum ama bu durumda, muhtemelen iç içe anahtar ifadeleri kullanırdım. Daha fazla yer kaplardı ama çok açık olurdu.
Mart'ta boyalar

Bu da işe yarayacaktı, ama sanırım bu bir tercih meselesi. Aslında kodların ne yaptığını söyleyen gibi ifadeler tercih ederim. Sizin fikriniz ne olursa olsun, fikrinizi bir kenara bırakmamak :). Yine de alternatif öneri için oy verin!
Joe Harper

12

Bakalım ne biliyoruz

1: cevaplarınız P1 (birinci oyuncu) ve P2 (ikinci oyuncu) için simetriktir. Bu bir dövüş oyunu için mantıklı ama aynı zamanda mantığınızı geliştirmek için yararlanabileceğiniz bir şey.

2: 3 vuruş 0 vuruş 2 vuruş 1 vuruş 3. Bu vakalarda ele alınmayan tek vakalar 0 vs 1 ve 2 vs 3 kombinasyonlarıdır. Başka bir deyişle, benzersiz zafer tablosu şöyle görünür: 0 vuruş 2, 1 vuruş 3, 2 vuruş 1, 3 vuruş 0.

3: Eğer 0/1 birbirlerine karşı çıkarsa, o zaman bir beraberlik berabere kalır, ancak 2/3 birbirlerine karşı çıkarsa, her ikisi de vurur

İlk olarak, kazanıp kazanmadığımızı söyleyen tek yönlü bir işlev geliştirelim:

// returns whether we beat our opponent
public boolean doesBeat(int attacker, int defender) {
  int[] beats = {2, 3, 1, 0};
  return defender == beats[attacker];
}

Daha sonra bu işlevi nihai sonucu oluşturmak için kullanabiliriz:

// returns the overall fight result
// bit 0 = one hits
// bit 1 = two hits
public int fightMath(int one, int two)
{
  // Check to see whether either has an outright winning combo
  if (doesBeat(one, two))
    return 1;

  if (doesBeat(two, one))
    return 2;

  // If both have 0/1 then its hitless draw but if both have 2/3 then they both hit.
  // We can check this by seeing whether the second bit is set and we need only check
  // one's value as combinations where they don't both have 0/1 or 2/3 have already
  // been dealt with 
  return (one & 2) ? 3 : 0;
}

Bu tartışmasız daha karmaşık ve muhtemelen birçok cevap sunulan tablo arama daha yavaş olsa da, aslında kodunuzun mantığını kapsadığı ve kodunuzu okuyan herkese açıklar çünkü üstün bir yöntem olduğuna inanıyorum. Bence bu daha iyi bir uygulama.

(Herhangi bir Java yaptığımdan beri, sözdizimi kapalıysa özür dilerim, umarım biraz yanlış anladıysam hala anlaşılabilir)

Bu arada, 0-3 açıkça bir şey ifade ediyor; bunlar rastgele değerler değildir, bu yüzden onları adlandırmaya yardımcı olur.


11

Umarım mantığı doğru anlarım. Nasıl bir şey hakkında:

public int fightMath (int one, int two)
{
    int oneHit = ((one == 3 && two != 1) || (one == 2 && two != 0)) ? 1 : 0;
    int twoHit = ((two == 3 && one != 1) || (two == 2 && one != 0)) ? 2 : 0;

    return oneHit+twoHit;
}

Bir vuruş yüksekinin veya bir vuruş düşükünün kontrol edilmesi engellenmez ve oyuncu iki için aynıdır.

Düzenleme: Algoritma tam olarak anlaşılmadı, ben fark etmedi engelleme sırasında ödül "hit" (Thx elias):

public int fightMath (int one, int two)
{
    int oneAttack = ((one == 3 && two != 1) || (one == 2 && two != 0)) ? 1 : (one >= 2) ? 2 : 0;
    int twoAttack = ((two == 3 && one != 1) || (two == 2 && one != 0)) ? 2 : (two >= 2) ? 1 : 0;

    return oneAttack | twoAttack;
}

Patter harika sonuç bulmanın yolu!
Çad

1
Yaklaşımdan hoşlanıyorum, ancak korkarım ki bu çözüm bir saldırıyı engelleyerek vurma olasılığından yoksun (örneğin, bir = 0 ve iki = 2 ise 0 döndürür, ancak spesifikasyona göre 1 bekleniyor). Belki doğru yapmak için üzerinde çalışabilirsiniz, ancak sonuç kodunun hala bu kadar zarif olacağından emin değilim, çünkü çizgiler biraz daha uzun büyüyeceği anlamına gelir.
elias

Blok için bir "hit" verildiğini fark etmedi. Gösterdiğiniz için teşekkürler. Çok basit bir düzeltme ile ayarlanmıştır.
Chris

10

Java ile deneyimim yok, bu yüzden bazı yazım hataları olabilir. Lütfen kodu sahte kod olarak kabul edin.

Basit bir anahtarla giderdim. Bunun için tek bir sayı değerlendirmesi yapmanız gerekir. Ancak, bu durumda, 0 <= one < 4 <= 9ve için 0 <= two < 4 <= 9, one10 ile çarparak ve ekleyerek her iki ints'ı basit bir int'e dönüştürebiliriz two. Sonra elde edilen sayıda aşağıdaki gibi bir anahtar kullanın:

public int fightMath(int one, int two) {
    // Convert one and two to a single variable in base 10
    int evaluate = one * 10 + two;

    switch(evaluate) {
        // I'd consider a comment in each line here and in the original code
        // for clarity
        case 0: result = 0; break;
        case 1: result = 0; break;
        case 1: result = 0; break;
        case 2: result = 1; break;
        case 3: result = 2; break;
        case 10: result = 0; break;
        case 11: result = 0; break;
        case 12: result = 2; break;
        case 13: result = 1; break;
        case 20: result = 2; break;
        case 21: result = 1; break;
        case 22: result = 3; break;
        case 23: result = 3; break;
        case 30: result = 1; break;
        case 31: result = 2; break;
        case 32: result = 3; break;
        case 33: result = 3; break;
    }

    return result;
}

Teorik bir kod olarak belirtmek istediğim başka bir kısa yöntem daha var. Ancak normalde uğraşmak istemediğiniz ekstra karmaşıklığa sahip olduğu için kullanmam. Ekstra karmaşıklık taban 4'ten gelir , çünkü sayma 0, 1, 2, 3, 10, 11, 12, 13, 20, ...

public int fightMath(int one, int two) {
    // Convert one and two to a single variable in base 4
    int evaluate = one * 4 + two;

    allresults = new int[] { 0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 1, 2, 3, 3 };

    return allresults[evaluate];
}

Java'dan bir şey kaçırmam durumunda gerçekten sadece ek not. PHP'de yapardım:

function fightMath($one, $two) {
    // Convert one and two to a single variable in base 4
    $evaluate = $one * 10 + $two;

    $allresults = array(
         0 => 0,  1 => 0,  2 => 1,  3 => 2,
        10 => 0, 11 => 0, 12 => 2, 13 => 1,
        20 => 2, 21 => 1, 22 => 3, 23 => 3,
        30 => 1, 31 => 2, 32 => 3, 33 => 3 );

    return $allresults[$evaluate];
}

Java'nın 8. sürümden önce hiç lamdaları yok
Kirill Gamazkov

1
Bu. Bu kadar az sayıda girdi için, kompozit değeri olan bir anahtar kullanırım (100 veya 1000 gibi 10'dan büyük bir çarpanla daha okunabilir olsa da).
Mart'ta Medinoc

7

İç içe ifkoşullu tercih ettiğiniz için , işte başka bir yol.
Üyeyi kullanmadığını resultve hiçbir durumu değiştirmediğini unutmayın.

public int fightMath(int one, int two) {
    if (one == 0) {
      if (two == 0) { return 0; }
      if (two == 1) { return 0; }
      if (two == 2) { return 1; }
      if (two == 3) { return 2; }
    }   
    if (one == 1) {
      if (two == 0) { return 0; }
      if (two == 1) { return 0; }
      if (two == 2) { return 2; }
      if (two == 3) { return 1; }
    }
    if (one == 2) {
      if (two == 0) { return 2; }
      if (two == 1) { return 1; }
      if (two == 2) { return 3; }
      if (two == 3) { return 3; }
    }
    if (one == 3) {
      if (two == 0) { return 1; }
      if (two == 1) { return 2; }
      if (two == 2) { return 3; }
      if (two == 3) { return 3; }
    }
    return DEFAULT_RESULT;
}

neden başka bir şeyin yok?
FDinoff

3
@FDinoff elseZincirleri kullanabilirdim ama hiç fark etmezdi .
Nick Dandoulakis

1
Önemsiz olduğunu biliyorum, ama başka zincirleri eklemek daha hızlı yürütmek olmaz mı? 4 vakanın 3'ünde? Her zaman sadece birkaç döngü olsa bile mümkün olduğunca hızlı yürütmek için kod yazma alışkanlığı kazanıyorum.
Brandon Bearden

2
@BrandonBearden burada herhangi bir fark yaratmayacaklar (girişin daima 0..3 aralığında olduğu varsayılarak). Derleyici muhtemelen kodu zaten mikro-optimize edecektir. Uzun bir else ifdeyim dizimiz varsa , kodu switchveya arama tablolarını hızlandırabiliriz.
Nick Dandoulakis

Bu nasıl? Eğerone==0 bu kod çalışır, o zaman kontrol etmek zorunda kalacak one==1sonra eğer one==2ve nihayet eğer one==3- ilk maçtan sonra açıklama çıkmak çünkü içeride, son üç çek vermeyeceğini eğer başka olsaydı. Ve evet, ifadelerin yerine bir switch ifadesi if (one...kullanarak ve daha sonra one's. Ancak, bu benim sorum değil.
Brandon Bearden

6

Anahtar muhafazası ile deneyin . ..

Bu konuda daha fazla bilgi için buraya veya buraya bir göz atın

switch (expression)
{ 
  case constant:
        statements;
        break;
  [ case constant-2:
        statements;
        break;  ] ...
  [ default:
        statements;
        break;  ] ...
}

Buna birden fazla koşul (aynı anda değil) ekleyebilir ve başka hiçbir durumun karşılanmadığı varsayılan bir seçeneğiniz bile olabilir .

Not: Sadece bir koşul sağlanacaksa ..

Aynı anda 2 koşul ortaya çıkarsa .. Anahtarın kullanılabileceğini sanmıyorum. Ancak kodunuzu burada azaltabilirsiniz.

Java anahtarı deyimi birden çok vaka


6

Bana gelen ilk şey, aslında Francisco Presencia tarafından verilen aynı cevaptı, ancak bir şekilde optimize edildi:

public int fightMath(int one, int two)
{
    switch (one*10 + two)
    {
    case  0:
    case  1:
    case 10:
    case 11:
        return 0;
    case  2:
    case 13:
    case 21:
    case 30:
        return 1;
    case  3:
    case 12:
    case 20:
    case 31:
        return 2;
    case 22:
    case 23:
    case 32:
    case 33:
        return 3;
    }
}

Son durumu (3 kişilik) varsayılan vaka yaparak daha da optimize edebilirsiniz:

    //case 22:
    //case 23:
    //case 32:
    //case 33:
    default:
        return 3;

Bu yöntemin avantajı , diğer önerilen yöntemlerden hangilerinin hangi değerlere oneve twohangi dönüş değerlerine karşılık geldiğini görmenin daha kolay olmasıdır .


Bu benim başka bir yanıt bir varyasyonu burada .
David R Tribble

6
((two&2)*(1+((one^two)&1))+(one&2)*(2-((one^two)&1)))/2

4
Buna ulaşmanız ne kadar sürdü?
mbatchkarov

2
@mbatchkarov Diğer cevapları okuduğunuzda yaklaşık 10 dakika, daha sonra kurşun kalem ve kağıtla 10 dakika sürün.
Dawood ibn Kareem

7
Bunu sürdürmek zorunda kalırsam çok üzülürdüm.
Meryovi

uhmmm ... Bir hata var: eksik; --unicorns
Alberto

@Meryovi ile hemfikirim, özlü olmak için sahne, ancak APL kodu gibi korkunç
Ed Griebel


3

Bir / iki ve sonuç arasında bir tablo çizerken, bir desen görüyorum,

if(one<2 && two <2) result=0; return;

Yukarıdaki ifadeler eğer en az 3 kesecektir. Ben bir set desen görmüyorum ne de verilen koddan çok bilgi almak mümkün - ama böyle bir mantık türetilebilir, if ifadeleri bir dizi kesecekti.

Bu yardımcı olur umarım.


3

Kurallar metin olarak tanımlamak iyi bir nokta olabilir, o zaman doğru formülü daha kolay elde edebilirsiniz. Bu laalto'nun güzel dizi temsilinden alınmıştır:

{ 0, 0, 1, 2 },
{ 0, 0, 2, 1 },
{ 2, 1, 3, 3 },
{ 1, 2, 3, 3 }

Ve burada bazı genel yorumlarla gidiyoruz, ancak bunları kural terimleriyle tanımlamanız gerekir:

if(one<2) // left half
{
    if(two<2) // upper left half
    {
        result = 0; //neither hits
    }
    else // lower left half
    {
        result = 1+(one+two)%2; //p2 hits if sum is even
    }
}
else // right half
{
    if(two<2) // upper right half
    {
        result = 1+(one+two+1)%2; //p1 hits if sum is even
    }
    else // lower right half
    {
        return 3; //both hit
    }
}

Elbette bunu daha az kodla karşılaştırabilirsiniz, ancak kompakt bir çözüm bulmak yerine neyi kodladığınızı anlamak genellikle iyi bir fikirdir.

if((one<2)&&(two<2)) result = 0; //top left
else if((one>1)&&(two>1)) result = 3; //bottom right
else result = 1+(one+two+((one>1)?1:0))%2; //no idea what that means

Karmaşık p1 / p2 hitleri hakkında bazı açıklamalar harika olurdu, ilginç görünüyor!


3

En kısa ve okunabilir çözüm:

static public int fightMath(int one, int two)
{
    if (one < 2 && two < 2) return 0;
    if (one > 1 && two > 1) return 3;
    int n = (one + two) % 2;
    return one < two ? 1 + n : 2 - n;
}

veya daha kısa:

static public int fightMath(int one, int two)
{
    if (one / 2 == two / 2) return (one / 2) * 3;
    return 1 + (one + two + one / 2) % 2;
}

Herhangi bir "sihirli" sayı içermez;) Umarım yardımcı olur.


2
Bu gibi formüller, bir kombinasyonun sonucunu daha sonraki bir tarihte değiştirmeyi (güncellemeyi) imkansız hale getirecektir. Tek yol formülün tamamını yeniden işlemektir.
SNag

2
@SNag: Buna katılıyorum. En esnek çözüm 2D dizisini kullanmaktır. Ama bu yazının yazarı bir formül istedi ve bu sadece basit ifs ve matematik ile alabileceğiniz en iyisi.
PW

2

static int val(int i, int u){ int q = (i & 1) ^ (u & 1); return ((i >> 1) << (1 ^ q))|((u >> 1) << q); }


1

Şahsen üçlü operatörleri kademelendirmeyi seviyorum:

int result = condition1
    ? result1
    : condition2
    ? result2
    : condition3
    ? result3
    : resultElse;

Ancak sizin durumunuzda şunları kullanabilirsiniz:

final int[] result = new int[/*16*/] {
    0, 0, 1, 2,
    0, 0, 2, 1,
    2, 1, 3, 3,
    1, 2, 3, 3
};

public int fightMath(int one, int two) {
    return result[one*4 + two];
}

Veya bit cinsinden bir desen fark edebilirsiniz:

one   two   result

section 1: higher bits are equals =>
both result bits are equals to that higher bits

00    00    00
00    01    00
01    00    00
01    01    00
10    10    11
10    11    11
11    10    11
11    11    11

section 2: higher bits are different =>
lower result bit is inverse of lower bit of 'two'
higher result bit is lower bit of 'two'

00    10    01
00    11    10
01    10    10
01    11    01
10    00    10
10    01    01
11    00    01
11    01    10

Böylece sihri kullanabilirsiniz:

int fightMath(int one, int two) {
    int b1 = one & 2, b2 = two & 2;
    if (b1 == b2)
        return b1 | (b1 >> 1);

    b1 = two & 1;

    return (b1 << 1) | (~b1);
}

1

İşte JAB'ın yanıtına benzer oldukça kısa bir versiyon . Bu, zafer kazanmak için başkalarının üzerinde hareket eden bir harita kullanır.

public enum Result {
  P1Win, P2Win, BothWin, NeitherWin;
}

public enum Move {
  BLOCK_HIGH, BLOCK_LOW, ATTACK_HIGH, ATTACK_LOW;

  static final Map<Move, List<Move>> beats = new EnumMap<Move, List<Move>>(
      Move.class);

  static {
    beats.put(BLOCK_HIGH, new ArrayList<Move>());
    beats.put(BLOCK_LOW, new ArrayList<Move>());
    beats.put(ATTACK_HIGH, Arrays.asList(ATTACK_LOW, BLOCK_LOW));
    beats.put(ATTACK_LOW, Arrays.asList(ATTACK_HIGH, BLOCK_HIGH));
  }

  public static Result compare(Move p1Move, Move p2Move) {
    boolean p1Wins = beats.get(p1Move).contains(p2Move);
    boolean p2Wins = beats.get(p2Move).contains(p1Move);

    if (p1Wins) {
      return (p2Wins) ? Result.BothWin : Result.P1Win;
    }
    if (p2Wins) {
      return (p1Wins) ? Result.BothWin : Result.P2Win;
    }

    return Result.NeitherWin;
  }
} 

Misal:

System.out.println(Move.compare(Move.ATTACK_HIGH, Move.BLOCK_LOW));

Baskılar:

P1Win

Bunun static final Map<Move, List<Move>> beats = new java.util.EnumMap<>();yerine tavsiye ederim , biraz daha verimli olmalı.
JAB

@JAB Evet, iyi fikir. Her zaman bu tipin varlığını unutuyorum. Ve ... bir tane yapmak ne kadar garip!
Duncan Jones

1

Bir Harita, bir HashMap veya bir TreeMap kullanırdım

Özellikle parametreler formda değilse 0 <= X < N

Bir dizi rastgele pozitif tamsayı gibi ..

kod

public class MyMap
{
    private TreeMap<String,Integer> map;

    public MyMap ()
    {
        map = new TreeMap<String,Integer> ();
    }

    public void put (int key1, int key2, Integer value)
    {
        String key = (key1+":"+key2);

        map.put(key, new Integer(value));
    }

    public Integer get (int key1, int key2)
    {
        String key = (key1+":"+key2);

        return map.get(key);
    }
}

1

Cevabının bir varyasyonunu kullandığım için @Joe Harper'a teşekkürler. Her 4 sonuç için 2 sonuç aynı olduğundan daha da inceltmek için daha da incelttim.

Bir noktada buna geri dönebilirim, ancak çoklu ifdurumlardan kaynaklanan büyük bir direnç yoksa o zaman şimdilik bunu saklayacağım. Tablo matrisine bakacağım ve deyim çözümlerini daha fazla değiştireceğim.

public int fightMath(int one, int two) {
  if (one === 0) {
    if (two === 2) { return 1; }
    else if(two === 3) { return 2; }
    else { return 0; }
  } else if (one === 1) {
    if (two === 2) { return 2; }
    else if (two === 3) { return 1; }
    else { return 0; }
  } else if (one === 2) {
    if (two === 0) { return 2; }
    else if (two === 1) { return 1; }
    else { return 3; }
  } else if (one === 3) {
    if (two === 0) { return 1; }
    else if (two === 1) { return 2; }
    else { return 3; }
  }
}

13
Bu aslında orijinalinden daha az okunabilir ve if ifadelerinin sayısını azaltmaz ...
Chad

@Chad Bunun amacı, işlem hızını artırmaktı ve korkunç görünmesine rağmen, gelecekte daha fazla eylem eklemem gerekirse kolayca güncellenebilir. Bunu söyleyerek şimdi daha önce tam olarak anlamadığım bir cevap kullanıyorum.
TomFirth

3
@ TomFirth84 if ifadeleriniz için uygun kodlama kurallarına uymamanızın bir nedeni var mı?
ylun.ca

@ ylun: Satırları, okunabilirlik için değil, spam alanı için SO'ya yapıştırmadan önce azaltmıştım. Bu sayfada pratik varyasyonları var ve ne yazık ki bu sadece öğrendiğim ve rahat olduğum gibi.
TomFirth

2
@ TomFirth84 ben yok bu kolayca hatlarının sayısı izin verilen değerlerin sayısı ürünü gibi bir şey büyür, güncellenir düşünüyorum.
Andrew Lazarus

0
  1. Kodu daha okunaklı hale getirmek için sabitleri veya sıralamaları kullanın
  2. Kodu daha fazla işleve ayırmaya çalışın
  3. Problemin simetrisini kullanmaya çalışın

İşte bunun nasıl görünebileceğine dair bir öneri, ancak burada bir ints kullanmak hala çirkin:

static final int BLOCK_HIGH = 0;
static final int BLOCK_LOW = 1;
static final int ATTACK_HIGH = 2;
static final int ATTACK_LOW = 3;

public static int fightMath(int one, int two) {
    boolean player1Wins = handleAttack(one, two);
    boolean player2Wins = handleAttack(two, one);
    return encodeResult(player1Wins, player2Wins); 
}



private static boolean handleAttack(int one, int two) {
     return one == ATTACK_HIGH && two != BLOCK_HIGH
        || one == ATTACK_LOW && two != BLOCK_LOW
        || one == BLOCK_HIGH && two == ATTACK_HIGH
        || one == BLOCK_LOW && two == ATTACK_LOW;

}

private static int encodeResult(boolean player1Wins, boolean player2Wins) {
    return (player1Wins ? 1 : 0) + (player2Wins ? 2 : 0);
}

Girdi ve çıktı için yapılandırılmış bir tür kullanmak daha iyi olurdu. Girdinin aslında iki alanı vardır: konum ve tür (blok veya saldırı). Çıktının ayrıca iki alanı vardır: player1Wins ve player2Wins. Bunu tek bir tamsayıya kodlamak kodu okumayı zorlaştırır.

class PlayerMove {
    PlayerMovePosition pos;
    PlayerMoveType type;
}

enum PlayerMovePosition {
    HIGH,LOW
}

enum PlayerMoveType {
    BLOCK,ATTACK
}

class AttackResult {
    boolean player1Wins;
    boolean player2Wins;

    public AttackResult(boolean player1Wins, boolean player2Wins) {
        this.player1Wins = player1Wins;
        this.player2Wins = player2Wins;
    }
}

AttackResult fightMath(PlayerMove a, PlayerMove b) {
    return new AttackResult(isWinningMove(a, b), isWinningMove(b, a));
}

boolean isWinningMove(PlayerMove a, PlayerMove b) {
    return a.type == PlayerMoveType.ATTACK && !successfulBlock(b, a)
            || successfulBlock(a, b);
}

boolean successfulBlock(PlayerMove a, PlayerMove b) {
    return a.type == PlayerMoveType.BLOCK 
            && b.type == PlayerMoveType.ATTACK 
            && a.pos == b.pos;
}

Ne yazık ki, Java bu tür veri türlerini ifade etmede çok iyi değil.


-2

Bunun yerine böyle bir şey yap

   public int fightMath(int one, int two) {
    return Calculate(one,two)

    }


    private int Calculate(int one,int two){

    if (one==0){
        if(two==0){
     //return value}
    }else if (one==1){
   // return value as per condtiion
    }

    }

4
Sadece genel işlev tarafından sarılmış özel bir işlev oluşturdunuz. Neden bunu sadece kamusal fonksiyonda uygulamakla kalmıyorsunuz?
Martin Ueding

5
Ve if ifadelerinin sayısını azaltmadınız.
Chad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.