Terlalu banyak pernyataan 'jika'?

263

Kode berikut tidak berfungsi seperti yang saya inginkan, tetapi jelek, berlebihan, atau beberapa hal lainnya. Saya telah melihat formula dan berusaha menulis beberapa solusi, tetapi saya berakhir dengan jumlah pernyataan yang sama.

Apakah ada jenis rumus matematika yang akan bermanfaat bagi saya dalam hal ini atau 16 jika pernyataan diterima?

Untuk menjelaskan kode, ini untuk jenis permainan berbasis giliran simultan .. dua pemain masing-masing memiliki empat tombol aksi dan hasilnya berasal dari sebuah array (0-3), tetapi variabel 'satu' & 'dua' dapat berupa ditugaskan apa pun jika ini membantu. Hasilnya adalah, 0 = tidak menang, 1 = p1 menang, 2 = p2 menang, 3 = keduanya menang.

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;
}
TomFirth
sumber
1
@waqaslam: - Ini dapat membantu Java beralih pernyataan untuk menangani dua variabel?
Rahul Tripathi
9
Tentunya ada beberapa logika di sini yang bisa digeneralisasi daripada dipaksakan dengan kasar? Tentunya ada beberapa fungsi f(a, b)yang menghasilkan jawaban dalam kasus umum? Anda belum menjelaskan logika perhitungan karena itu semua jawabannya hanya lipstik pada seekor babi. Saya akan mulai dengan serius memikirkan kembali logika program Anda, menggunakan intflags untuk tindakan sangat ketinggalan jaman. enums dapat berisi logika dan deskriptif, ini akan memungkinkan Anda untuk menulis kode Anda dengan cara yang lebih modern.
Boris the Spider
Setelah membaca jawaban @Steve Benett yang disediakan dalam pertanyaan alternatifnya yang ditautkan di atas, saya dapat berasumsi tidak ada jawaban rumus langsung untuk ini karena pada dasarnya sama dengan database. Saya berusaha menjelaskan dalam pertanyaan awal bahwa saya membuat game sederhana (petarung) dan pengguna memiliki pilihan 4 tombol: blockHigh (0), blockLow (1), attackHigh (2) dan attackLow (3). Angka-angka ini disimpan dalam array sampai dibutuhkan. Kemudian mereka digunakan oleh fungsi 'fightMath ()' yang memanggil pilihan playerOne melawan playerTwos untuk memberikan hasilnya. Tidak ada deteksi tabrakan yang sebenarnya.
TomFirth
9
Jika Anda punya jawaban, silakan posting seperti itu. Diskusi panjang dalam komentar sulit untuk diikuti, terutama ketika kode terlibat. Jika Anda ingin berbicara tentang apakah pertanyaan ini seharusnya dimigrasi ke Tinjauan Kode, ada diskusi Meta tentang itu.
George Stocker
1
Apa yang Anda maksud dengan "sama dengan database"? Jika nilai-nilai ini ada di database, tarik dari sana. Kalau tidak, jika ini benar-benar kompleks ini, saya akan membiarkannya seperti yang Anda miliki dan menambahkan komentar logika bisnis setelah setiap baris sehingga orang mengerti apa yang sedang terjadi. Lebih baik (bagi saya) panjang dan eksplisit - seseorang di masa depan dapat memahami apa yang sedang terjadi. Jika Anda meletakkannya di peta atau mencoba menyimpan 8 baris kode, sisi positifnya sangat kecil, dan perampingannya lebih besar: Anda membuatnya semakin membingungkan bagi seseorang yang perlu membaca kode Anda suatu hari.
skaz

Jawaban:

600

Jika Anda tidak bisa membuat formula, Anda bisa menggunakan tabel untuk hasil yang terbatas:

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];
laalto
sumber
7
Ini menarik karena saya belum pernah melihat solusi ini sebelumnya. Saya tidak yakin saya memahami hasil pengembalian tetapi akan menikmati pengujian itu.
TomFirth
4
Anda tidak perlu menegaskan, Java akan IndexOutOfBoundsExceptiontetap melemparkan jika satu atau lebih indeks berada di luar batas.
JAB
43
@JoeHarper Jika Anda ingin sesuatu yang mudah dibaca, Anda tidak akan menggunakan angka ajaib di awal dan Anda akan memiliki komentar yang menjelaskan pemetaan. Karena itu, saya lebih suka versi ini daripada yang asli, tetapi untuk sesuatu yang dapat dipertahankan dalam jangka panjang saya akan menggunakan pendekatan yang melibatkan jenis yang disebutkan atau setidaknya disebut konstanta.
JAB
13
@JoeHarper "Secara teoritis" adalah satu hal, "praktis" adalah hal lain. Tentu saja saya mencoba menggunakan penamaan deskriptif (dengan pengecualian dari i/ j/ kkonvensi untuk variabel loop), bernama konstanta, mengatur kode saya dengan cara yang dapat dibaca, dll., Tetapi ketika variabel dan nama fungsi mulai mengambil lebih dari 20 karakter setiap saya menemukan itu benar-benar mengarah pada kode yang kurang mudah dibaca. Pendekatan saya yang biasa adalah mencoba untuk kode yang komprehensif tetapi ringkas dengan komentar di sana-sini untuk menjelaskan mengapa kode tersebut terstruktur seperti itu (vs bagaimana). Menempatkan mengapa dalam nama hanya mengacaukan segalanya.
JAB
13
Saya suka solusi ini untuk masalah khusus ini karena hasil sebenarnya didikte oleh matriks hasil.
Mencoba
201

Karena kumpulan data Anda sangat kecil, Anda dapat memampatkan semuanya menjadi 1 bilangan bulat panjang dan mengubahnya menjadi rumus

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

Varian bitwise lainnya:

Ini memanfaatkan fakta bahwa semuanya adalah kelipatan dari 2

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

The Origin of the Magic Constant

Apa yang bisa kukatakan? Dunia membutuhkan sihir, kadang-kadang kemungkinan sesuatu membutuhkan penciptaannya.

Inti dari fungsi yang memecahkan masalah OP adalah peta dari 2 angka (satu, dua), domain {0,1,2,3} hingga rentang {0,1,2,3}. Setiap jawaban telah mendekati cara mengimplementasikan peta itu.

Juga, Anda dapat melihat dalam sejumlah jawaban pernyataan kembali masalah sebagai peta 1 basis 2-digit 4 nomor N (satu, dua) di mana satu adalah digit 1, dua adalah digit 2, dan N = 4 * satu + dua; N = {0,1,2, ..., 15} - enam belas nilai yang berbeda, itu penting. Output dari fungsi adalah satu basis 1 digit 4 angka {0,1,2,3} - 4 nilai yang berbeda, juga penting.

Sekarang, nomor basis 4 digit 1 dapat dinyatakan sebagai nomor basis 2 digit 2; {0,1,2,3} = {00,01,10,11}, sehingga setiap output dapat dikodekan dengan hanya 2 bit. Dari atas, hanya ada 16 output yang berbeda yang mungkin, jadi 16 * 2 = 32 bit adalah semua yang diperlukan untuk menyandikan seluruh peta; ini semua bisa masuk ke dalam 1 integer.

Konstanta M adalah penyandian peta m di mana m (0) dikodekan dalam bit M [0: 1], m (1) dikodekan dalam bit M [2: 3], dan m (n) dikodekan dalam bit M [n * 2: n * 2 + 1].

Yang tersisa hanyalah pengindeksan dan mengembalikan bagian kanan konstanta, dalam hal ini Anda dapat menggeser M kanan 2 * N kali dan mengambil 2 bit paling tidak signifikan, yaitu (M >> 2 * N) & 0x3. Ekspresi (satu << 3) dan (dua << 1) hanya mengalikan hal sambil mencatat bahwa 2 * x = x << 1 dan 8 * x = x << 3.

waTeim
sumber
79
pintar, tetapi tidak ada orang lain yang membaca kode akan memiliki kesempatan untuk memahaminya.
Aran Mulholland
106
Saya pikir ini adalah praktik yang sangat buruk. Tidak ada orang lain kecuali penulis akan mengerti itu. Anda ingin melihat sepotong kode dan memahaminya dengan cepat. Tapi ini hanya buang-buang waktu saja.
Balázs Németh
14
Saya dengan @ BalázsMáriaNémeth tentang ini. Meskipun sangat mengesankan, Anda harus membuat kode untuk psikopat yang kejam!
OrhanC1
90
Semua downvoters berpikir bahwa ini adalah bau kode yang mengerikan. Semua pendukung berpikir sama, tetapi mengagumi kepintaran di belakangnya. +1 (Jangan pernah menggunakan kode ini.)
usr
4
Sungguh contoh yang bagus untuk menulis kode saja !
lealand
98

Saya tidak suka solusi yang disajikan kecuali untuk JAB. Tidak ada yang lain membuatnya mudah untuk membaca kode dan memahami apa yang sedang dihitung .

Inilah cara saya akan menulis kode ini - Saya hanya tahu C #, bukan Java, tetapi Anda mendapatkan gambar:

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

Sekarang jauh lebih jelas apa yang sedang dihitung di sini: ini menekankan bahwa kita menghitung siapa yang terkena serangan apa, dan mengembalikan kedua hasil.

Namun ini bisa menjadi lebih baik; array Boolean agak buram. Saya suka pendekatan pencarian tabel tetapi saya akan cenderung untuk menuliskannya sedemikian rupa sehingga memperjelas apa yang dimaksud dengan semantik game yang dimaksud. Artinya, daripada "serangan nol dan pertahanan satu hasil tanpa pukulan", alih-alih menemukan cara untuk membuat kode lebih jelas menyiratkan "serangan tendangan rendah dan pertahanan blok rendah menghasilkan tanpa serangan". Buat kodenya mencerminkan logika bisnis gim.

Eric Lippert
sumber
66
Omong kosong. Kebanyakan program yang sedikit berpengalaman akan dapat menghargai saran yang diberikan di sini, dan menerapkan gaya pengkodean untuk bahasa mereka sendiri. Pertanyaannya adalah bagaimana menghindari serangkaian seandainya. Ini menunjukkan caranya.
GreenAsJade
6
@ user3414693: Saya tahu betul bahwa ini adalah pertanyaan Java. Jika Anda membaca jawabannya dengan cermat, itu menjadi jelas. Jika Anda percaya bahwa jawaban saya tidak bijak maka saya mendorong Anda untuk menuliskan jawaban Anda sendiri yang Anda sukai.
Eric Lippert
1
@EricLippert Saya suka solusi JAB juga. IMHO, ketik enum dalam C # menyisakan banyak yang diinginkan. Itu tidak mengikuti lubang filosofi kesuksesan yang dilakukan oleh fitur-fitur lainnya. Misalnya stackoverflow.com/a/847353/92414 Apakah tim c # punya rencana untuk membuat tipe enum baru (untuk menghindari pemecahan kode yang ada) yang dirancang lebih baik?
SolutionYogi
@SolutionYogi: Saya juga tidak terlalu suka enum di C #, meskipun mereka memang demikian karena alasan sejarah yang bagus. (Sebagian besar untuk kompatibilitas dengan COM enums yang ada.) Saya tidak mengetahui adanya rencana untuk menambahkan gear baru untuk enums di C # 6.
Eric Lippert
3
@ Tidak, tidak ada komentar yang tidak berjalan. OP melakukan persis apa yang harus dilakukan; konversi komentar menjadi kode yang jelas. Lihat misalnya, Steve McConnell Code, lengkapi stevemcconnell.com/cccntnt.htm
djechlin
87

Anda dapat membuat matriks yang berisi hasil

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

Saat Anda ingin mendapatkan nilai, Anda akan menggunakannya

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

Orang lain telah menyarankan ide awal saya, metode matriks, tetapi selain mengkonsolidasikan pernyataan if, Anda dapat menghindari sebagian dari apa yang Anda miliki dengan memastikan argumen yang disediakan berada dalam kisaran yang diharapkan dan dengan menggunakan pengembalian di tempat (beberapa pengkodean standar yang saya lihat menerapkan satu titik keluar untuk fungsi, tetapi saya telah menemukan bahwa banyak pengembalian sangat berguna untuk menghindari pengkodean panah dan dengan prevalensi pengecualian di Jawa tidak ada banyak gunanya secara ketat menegakkan aturan seperti itu pula karena setiap pengecualian yang tidak tertangkap yang dilemparkan ke dalam metode ini mungkin adalah titik keluar). Pernyataan peralihan yang bersarang adalah suatu kemungkinan, tetapi untuk rentang nilai yang kecil yang Anda periksa di sini, saya menemukan jika pernyataan menjadi lebih ringkas dan tidak cenderung menghasilkan banyak perbedaan kinerja,

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
}

Ini akhirnya menjadi kurang dapat dibaca daripada mungkin karena ketidakteraturan bagian-bagian dari pemetaan input-> hasil. Saya lebih menyukai gaya matriks karena kesederhanaannya dan bagaimana Anda dapat mengatur matriks agar masuk akal secara visual (meskipun itu sebagian dipengaruhi oleh ingatan saya akan peta Karnaugh):

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

Pembaruan: Mengingat Anda menyebutkan pemblokiran / pemukulan, berikut ini adalah perubahan yang lebih radikal pada fungsi yang menggunakan tipe enumerated properti-holding yang disebutkan untuk input dan hasilnya dan juga memodifikasi hasil sedikit untuk memperhitungkan pemblokiran, yang akan menghasilkan lebih banyak fungsi yang dapat dibaca.

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

Anda bahkan tidak perlu mengubah fungsi itu sendiri jika Anda ingin menambahkan blok / serangan yang lebih tinggi, hanya enum; menambahkan jenis gerakan tambahan mungkin akan membutuhkan modifikasi fungsi. Juga, EnumSets mungkin lebih dapat diperluas daripada menggunakan enum tambahan sebagai properti enum utama, misalnya EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...);dan kemudian attacks.contains(move)daripada move.type == MoveType.ATTACK, meskipun menggunakan EnumSets mungkin akan sedikit lebih lambat daripada langsung sama dengan cek.


Untuk kasus di mana blok yang berhasil menghasilkan penghitung, Anda dapat menggantinya if (one.height == two.height) return LandedHit.NEITHER;dengan

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

Juga, mengganti beberapa ifpernyataan dengan penggunaan operator ternary ( boolean_expression ? result_if_true : result_if_false) dapat membuat kode lebih kompak (misalnya, kode di blok sebelumnya akan menjadi return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;), tetapi itu dapat menyebabkan oneliners yang lebih sulit dibaca sehingga saya tidak akan ' t merekomendasikannya untuk percabangan yang lebih kompleks.

TUSUKAN
sumber
Saya pasti akan melihat ini tetapi kode saya saat ini memungkinkan saya untuk menggunakan nilai int onedan twodigunakan kembali sebagai titik awal pada spritesheet saya. Meskipun tidak memerlukan banyak kode tambahan untuk memungkinkannya.
TomFirth
2
@ TomFirth84 Ada EnumMapkelas yang bisa Anda gunakan untuk memetakan enum ke offset integer Anda (Anda juga bisa menggunakan nilai ordinal anggota enum secara langsung, misalnya Move.ATTACK_HIGH.ordinal()akan 0, Move.ATTACK_LOW.ordinal()akan 1, dll., Tapi itu lebih rapuh / kurang fleksibel daripada secara eksplisit mengasosiasikan setiap anggota dengan nilai sebagai menambahkan nilai enum di antara yang sudah ada akan membuang hitungan, yang tidak akan menjadi kasus dengan EnumMap.)
JAB
7
Ini adalah solusi yang paling mudah dibaca karena menerjemahkan kode menjadi sesuatu yang bermakna bagi orang yang membaca kode.
David Stanley
Kode Anda, setidaknya yang menggunakan enum, salah. Menurut pernyataan if di OP blok sukses menyebabkan hit pada penyerang. Tapi +1 untuk kode yang bermakna.
Taemyr
2
Anda bahkan dapat menambahkan attack(against)metode ke Moveenum, mengembalikan HIT ketika langkah itu adalah serangan yang berhasil, BACKFIRE ketika langkah itu adalah serangan yang diblokir, dan TIDAK ADA saat itu bukan serangan. Dengan cara ini Anda dapat mengimplementasikannya secara umum ( public boolean attack(Move other) { if this.isAttack() return (other.isAttack() || other.height != this.height) ? HIT : BACKFIRE; return NOTHING; }), dan menimpanya pada gerakan tertentu saat dibutuhkan (gerakan lemah yang dapat diblokir oleh blok mana pun, serangan yang tidak pernah menjadi bumerang, dll.)
ditulis ulang
50

Mengapa tidak menggunakan array?

Saya akan mulai dari awal. Saya melihat sebuah pola, nilainya berubah dari 0 menjadi 3 dan Anda ingin menangkap semua nilai yang mungkin. Ini meja Anda:

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

ketika kita melihat tabel biner yang sama ini kita melihat hasil berikut:

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

Sekarang mungkin Anda sudah melihat beberapa pola tetapi ketika saya menggabungkan nilai satu dan dua, saya melihat bahwa Anda menggunakan semua nilai 0000, 0001, 0010, ..... 1110 dan 1111. Sekarang mari kita gabungkan nilai satu dan dua untuk membuat satu 4 bit integer.

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

Ketika kami menerjemahkan ini kembali ke nilai desimal, kami melihat array nilai yang sangat memungkinkan di mana gabungan satu dan dua dapat digunakan sebagai indeks:

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

Array kemudian {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3}, di mana indeksnya hanya satu dan dua digabungkan.

Saya bukan programmer Java, tetapi Anda bisa menghilangkan semua pernyataan if dan menuliskannya sebagai berikut:

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

Saya tidak tahu apakah bitshift 2 lebih cepat dari multiplikasi. Tapi itu bisa dicoba.

dj bazzie wazzie
sumber
2
Bit-shift 2 hampir pasti lebih cepat daripada multiplikasi 4. Paling-paling, multiplikasi oleh 4, akan mengenali bahwa 4 adalah 2 ^ 2 dan melakukan sedikit pergeseran itu sendiri (diterjemahkan oleh kompiler secara potensial). Terus terang, bagi saya, perubahan itu lebih mudah dibaca.
Cruncher
Saya suka pendekatan Anda! Ini pada dasarnya meratakan matriks 4x4 menjadi array 16 elemen.
Cameron Tinker
6
Saat ini, jika saya tidak salah, kompiler pasti akan mengenali bahwa Anda mengalikannya dengan kekuatan dua dan mengoptimalkannya sesuai. Jadi bagi Anda, programmer, perubahan bit dan perkalian harus memiliki kinerja yang persis sama.
Tanner Swett
24

Ini menggunakan sedikit bitmagic (Anda sudah melakukannya dengan memegang dua bit informasi (rendah / tinggi & serang / blok) dalam satu integer):

Saya belum menjalankannya, hanya mengetiknya di sini, tolong klik dua kali. Idenya pasti berhasil. EDIT: Sekarang diuji untuk setiap input, berfungsi dengan baik.

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

Atau haruskah saya menyarankan untuk memisahkan dua bit informasi menjadi variabel yang terpisah? Kode sebagian besar didasarkan pada operasi bit seperti ini di atas biasanya sangat sulit untuk dipelihara.

elias
sumber
2
Saya setuju dengan solusi ini, sangat mirip dengan apa yang ada dalam pikiran saya dalam komentar saya pada pertanyaan utama. Saya lebih suka membaginya menjadi variabel yang terpisah, yang akan membuatnya lebih mudah untuk menambahkan serangan tengah misalnya di masa depan.
Yoh
2
Saya baru saja memperbaiki beberapa bug pada kode di atas setelah mengujinya, sekarang berfungsi dengan baik. Melangkah lebih jauh dengan cara bit-manipulator, saya juga datang dengan solusi satu baris, yang masih tidak semistik bitmask dalam jawaban lain, tetapi masih cukup rumit untuk mengacaukan pikiran Anda:return ((one ^ two) & 2) == 0 ? (one & 2) / 2 * 3 : ((one & 2) / 2 ^ ((one ^ two) & 1)) + 1;
elias
1
Ini adalah jawaban terbaik karena setiap programmer baru membacanya akan benar-benar memahami keajaiban yang terjadi di balik semua angka ajaib itu.
bezmax
20

Sejujurnya, setiap orang memiliki gaya kode mereka sendiri. Saya tidak akan berpikir kinerja akan terlalu terpengaruh. Jika Anda memahami ini lebih baik daripada menggunakan versi sakelar, teruskan menggunakan ini.

Anda bisa membuat sarang jika, sehingga berpotensi akan ada sedikit peningkatan kinerja untuk yang terakhir jika memeriksa karena tidak akan melalui banyak jika pernyataan. Tetapi dalam konteks Anda tentang kursus dasar Java mungkin tidak akan menguntungkan.

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

Jadi, bukannya ...

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

Kamu akan melakukan ...

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

Dan cukup format ulang sesuai keinginan Anda.

Ini tidak membuat kode terlihat lebih baik, tetapi saya pikir berpotensi mempercepatnya.

Joe Harper
sumber
3
Tidak tahu apakah ini benar-benar praktik yang baik tetapi untuk kasus ini, saya mungkin akan menggunakan pernyataan switch bersarang. Ini akan membutuhkan lebih banyak ruang tetapi akan sangat jelas.
dyesdyes
Itu juga akan berhasil, tapi saya kira ini masalah preferensi. Saya sebenarnya lebih suka jika pernyataan seperti itu hampir mengatakan apa yang dilakukan kode. Tidak meletakkan pendapat Anda tentu saja, apa pun yang sesuai untuk Anda :). Suara positif untuk saran alternatif sekalipun!
Joe Harper
12

Mari kita lihat apa yang kita ketahui

1: jawaban Anda simetris untuk P1 (pemain satu) dan P2 (pemain dua). Ini masuk akal untuk gim pertempuran, tetapi juga sesuatu yang bisa Anda manfaatkan untuk meningkatkan logika Anda.

2: 3 ketukan 0 ketukan 2 ketukan 1 ketukan 3. Satu-satunya kasus yang tidak dicakup oleh kasus ini adalah kombinasi dari 0 vs 1 dan 2 vs 3. Dengan kata lain tabel kemenangan yang unik terlihat seperti ini: 0 ketukan 2, 1 ketukan 3, 2 ketukan 1, 3 ketukan 0.

3: Jika 0/1 melawan satu sama lain maka ada hasil imbang tanpa hit tetapi jika 2/3 naik melawan masing-masing maka keduanya memukul

Pertama, mari kita bangun fungsi satu arah untuk memberi tahu kita jika kita menang:

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

Kami kemudian dapat menggunakan fungsi ini untuk menyusun hasil akhir:

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

Walaupun ini bisa dibilang lebih kompleks dan mungkin lebih lambat daripada pencarian tabel yang ditawarkan dalam banyak jawaban, saya percaya ini adalah metode yang unggul karena sebenarnya merangkum logika kode Anda dan menjelaskannya kepada siapa pun yang membaca kode Anda. Saya pikir ini membuatnya menjadi implementasi yang lebih baik.

(Sudah lama sejak saya melakukan Java, jadi minta maaf jika sintaks dimatikan, mudah-mudahan masih dapat dimengerti jika saya salah mengerti)

By the way, 0-3 jelas berarti sesuatu; mereka bukan nilai yang sewenang-wenang sehingga akan membantu untuk memberi nama mereka.

Jack Aidley
sumber
11

Saya harap saya mengerti logikanya dengan benar. Bagaimana dengan sesuatu seperti:

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

Memeriksa satu hit tinggi atau satu hit rendah tidak diblokir dan sama untuk pemain dua.

Sunting: Algoritma tidak sepenuhnya dipahami, "hit" diberikan ketika memblokir yang tidak saya sadari (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;
}
Chris
sumber
Cara untuk menemukan hasil yang bagus!
Chad
1
Saya suka pendekatannya, tapi saya khawatir solusi ini sama sekali tidak memiliki kemungkinan untuk memukul dengan memblokir serangan (misalnya jika satu = 0 dan dua = 2 mengembalikan 0, tetapi 1 diharapkan sesuai dengan spesifikasi). Mungkin Anda bisa mengusahakannya untuk memperbaikinya, tetapi saya tidak yakin kode yang dihasilkan akan tetap seanggun ini, karena ini berarti garis-garisnya akan tumbuh agak lebih panjang.
elias
Tidak menyadari bahwa "hit" diberikan untuk blok. Terima kasih telah menunjukkannya. Disesuaikan dengan perbaikan yang sangat sederhana.
Chris
10

Saya tidak punya pengalaman dengan Java jadi mungkin ada beberapa kesalahan ketik. Silakan pertimbangkan kode ini sebagai kode semu.

Saya akan pergi dengan saklar sederhana. Untuk itu, Anda perlu evaluasi nomor tunggal. Namun, untuk kasus ini, karena 0 <= one < 4 <= 9dan 0 <= two < 4 <= 9, kita dapat mengonversi kedua int menjadi int sederhana dengan mengalikannya onedengan 10 dan menambahkan two. Kemudian gunakan saklar di nomor yang dihasilkan seperti ini:

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

Ada metode pendek lain yang saya ingin tunjukkan sebagai kode teoritis. Namun saya tidak akan menggunakannya karena memiliki beberapa kompleksitas tambahan yang biasanya tidak ingin Anda tangani. Kompleksitas ekstra berasal dari basis 4 , karena penghitungan adalah 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];
}

Benar-benar hanya catatan tambahan, kalau-kalau saya kehilangan sesuatu dari Jawa. Dalam PHP saya akan melakukan:

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];
}
Francisco Presencia
sumber
Java tidak memiliki lamdas sebelum versi ke-8
Kirill Gamazkov
1
Ini. Untuk sejumlah kecil input, saya akan menggunakan switch dengan nilai komposit (meskipun mungkin lebih mudah dibaca dengan pengali lebih besar dari 10, seperti 100 atau 1000).
Medinoc
7

Karena Anda lebih suka bersarang ifkondisi, inilah cara lain.
Perhatikan bahwa itu tidak menggunakan resultanggota dan itu tidak mengubah keadaan apa pun.

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;
}
Nick Dandoulakis
sumber
kenapa kamu tidak punya yang lain?
FDinoff
3
@Finoff aku bisa menggunakan elserantai tapi itu tidak membuat perbedaan.
Nick Dandoulakis
1
Saya tahu ini sepele, tetapi tidak akan menambahkan rantai lain mengeksekusi lebih cepat? dalam 3 dari 4 kasus? Saya selalu membiasakan menulis kode untuk mengeksekusi secepat mungkin bahkan jika itu hanya beberapa siklus.
Brandon Bearden
2
@BrandonBearden di sini mereka tidak akan membuat perbedaan (dengan asumsi input selalu di kisaran 0..3). Kompiler mungkin akan mengoptimalkan mikro kode. Jika kita memiliki serangkaian else ifpernyataan panjang, kita dapat mempercepat kode dengan switchatau mencari tabel.
Nick Dandoulakis
Bagaimana bisa begitu? Jika one==0akan menjalankan kode, maka harus memeriksa jika one==1lalu jika one==2dan akhirnya jika one==3- Jika ada yang lain di sana, itu tidak akan melakukan tiga pemeriksaan terakhir karena akan keluar dari pernyataan setelah pertandingan pertama. Dan ya, Anda bisa lebih mengoptimalkan dengan menggunakan pernyataan switch di tempat if (one...pernyataan dan kemudian menggunakan switch lain di dalam kasus ini one's. Namun, itu bukan pertanyaan saya.
Brandon Bearden
6

Cobalah dengan saklar casing. ..

Lihatlah di sini atau di sini untuk info lebih lanjut tentang itu

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

Anda dapat menambahkan beberapa kondisi (tidak secara bersamaan) dan bahkan memiliki opsi default di mana tidak ada kasus lain telah terpenuhi.

PS: Hanya kalau satu syarat harus dipenuhi ..

Jika 2 kondisi muncul secara bersamaan .. Saya rasa switch tidak dapat digunakan. Tetapi Anda dapat mengurangi kode Anda di sini.

Java beralih pernyataan beberapa kasus

Nevin Madhukar K
sumber
6

Hal pertama yang terjadi pada saya pada dasarnya adalah jawaban yang sama yang diberikan oleh Francisco Presencia, tetapi agak dioptimalkan:

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

Anda dapat lebih mengoptimalkannya dengan menjadikan case terakhir (untuk 3) sebagai case default:

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

Keuntungan dari metode ini adalah bahwa lebih mudah untuk melihat nilai untuk onedan twosesuai dengan nilai yang dikembalikan dari beberapa metode lain yang disarankan.

David R Tribble
sumber
Ini adalah variasi dari jawaban saya yang lain di sini .
David R Tribble
6
((two&2)*(1+((one^two)&1))+(one&2)*(2-((one^two)&1)))/2
Dawood ibn Kareem
sumber
4
Berapa lama Anda sampai di sini?
mbatchkarov
2
@mbatchkarov Sekitar 10 menit membaca jawaban lain, lalu 10 menit menulis dengan pensil dan kertas.
Dawood ibn Kareem
7
Saya akan sangat sedih jika saya harus mempertahankan ini.
Meryovi
uhmmm ... Ada bug: Anda hilang; --unicorns
Alberto
Saya setuju dengan @Meryovi, alat peraga untuk ringkas, namun mengerikan seperti kode APL
Ed Griebel
4

Anda dapat menggunakan sakelar alih-alih mutipleif

Juga menyebutkan bahwa karena Anda memiliki dua variabel maka Anda harus menggabungkan kedua variabel untuk menggunakannya secara bergantian

Periksa pernyataan beralih Java ini untuk menangani dua variabel?

Rahul Tripathi
sumber
3

Saat saya menggambar tabel antara satu / dua dan hasilnya, saya melihat satu pola,

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

Pernyataan di atas akan mengurangi minimal 3 jika pernyataan. Saya tidak melihat pola yang ditetapkan atau saya bisa mendapatkan banyak dari kode yang diberikan - tetapi jika logika tersebut dapat diturunkan, itu akan mengurangi sejumlah pernyataan if.

Semoga ini membantu.

AnonNihcas
sumber
3

Poin yang baik adalah mendefinisikan aturan sebagai teks, Anda dapat dengan mudah mendapatkan rumus yang benar. Ini diekstrak dari representasi array bagus laalto:

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

Dan di sini kita pergi dengan beberapa komentar umum, tetapi Anda harus menggambarkannya dalam istilah aturan:

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

Tentu saja Anda bisa memecahnya menjadi lebih sedikit kode, tetapi umumnya merupakan ide bagus untuk memahami kode apa yang Anda miliki daripada mencari solusi yang ringkas.

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

Beberapa penjelasan tentang hit p1 / p2 yang rumit akan sangat bagus, terlihat menarik!

Marcellus
sumber
3

Solusi terpendek dan masih dapat dibaca:

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

atau bahkan lebih pendek:

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

Tidak mengandung angka "ajaib";) Semoga ini bisa membantu.

PW
sumber
2
Formula seperti ini akan membuat tidak mungkin untuk mengubah (memperbarui) hasil kombinasi di kemudian hari. Satu-satunya cara adalah mengerjakan ulang seluruh rumus.
SNag
2
@ Nat: Saya setuju dengan itu. Solusi paling fleksibel adalah menggunakan array 2D. Tetapi autor dari postingan ini menginginkan formula dan ini adalah yang terbaik yang bisa Anda dapatkan dengan hanya jika dan matematika sederhana.
PW
2

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

pengguna1837841
sumber
1

Secara pribadi saya suka membuat operator ternary:

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

Tetapi dalam kasus Anda, Anda dapat menggunakan:

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

Atau, Anda dapat melihat pola dalam bit:

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

Jadi Anda bisa menggunakan sihir:

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);
}
Kirill Gamazkov
sumber
1

Ini versi yang cukup ringkas, mirip dengan respons JAB . Ini menggunakan peta untuk menyimpan yang bergerak menang atas yang lain.

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

Contoh:

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

Cetakan:

P1Win
Duncan Jones
sumber
Saya akan merekomendasikan static final Map<Move, List<Move>> beats = new java.util.EnumMap<>();sebagai gantinya, itu harus sedikit lebih efisien.
JAB
@ JAB Ya, ide bagus. Saya selalu lupa bahwa tipe itu ada. Dan ... betapa canggungnya membuat itu!
Duncan Jones
1

Saya akan menggunakan Peta, baik HashMap atau TreeMap

Apalagi jika parameternya tidak pada formulir 0 <= X < N

Seperti satu set bilangan bulat positif acak ..

Kode

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);
    }
}
Khaled.K
sumber
1

Terima kasih kepada @ Jooe Harper karena saya akhirnya menggunakan variasi jawabannya. Untuk menurunkannya lebih jauh karena 2 hasil per 4 adalah sama, saya menurunkannya lebih jauh.

Saya mungkin kembali ke ini di beberapa titik, tetapi jika tidak ada perlawanan besar yang disebabkan oleh beberapa ifpernyataan maka saya akan menyimpan ini untuk saat ini. Saya akan melihat matriks tabel dan beralih solusi pernyataan lebih lanjut.

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; }
  }
}
TomFirth
sumber
13
Ini sebenarnya kurang dapat dibaca daripada yang asli dan tidak mengurangi jumlah jika pernyataan ...
Chad
@Chad Gagasan ini adalah untuk meningkatkan kecepatan proses dan meskipun terlihat mengerikan tetapi mudah diperbarui jika saya menambahkan lebih banyak tindakan di masa depan. Mengatakan ini, saya sekarang menggunakan jawaban sebelumnya yang sebelumnya tidak saya mengerti.
TomFirth
3
@ TomFirth84 Apakah ada alasan bahwa Anda tidak mengikuti konvensi pengkodean yang tepat untuk pernyataan if Anda?
ylun.ca
@ylun: Saya telah mengurangi garis sebelum menempelkannya pada SO, bukan untuk keterbacaan tetapi untuk ruang spam belaka. Ada variasi latihan di halaman ini dan sayangnya itu hanya cara saya telah belajar dan merasa nyaman.
TomFirth
2
@ TomFirth84 Saya tidak berpikir ini mudah diperbarui, jumlah baris bertambah seperti produk dari jumlah nilai yang diizinkan.
Andrew Lazarus
0
  1. Gunakan konstanta atau enum untuk membuat kode lebih mudah dibaca
  2. Cobalah untuk membagi kode menjadi lebih banyak fungsi
  3. Cobalah menggunakan simetri masalah

Berikut adalah saran bagaimana ini terlihat, tetapi menggunakan int di sini masih agak jelek:

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

Akan lebih baik untuk menggunakan tipe terstruktur untuk input dan output. Input sebenarnya memiliki dua bidang: posisi dan tipe (blok atau serangan). Outputnya juga memiliki dua bidang: player1Wins dan player2Wins. Pengkodean ini menjadi satu bilangan bulat membuat lebih sulit untuk membaca kode.

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

Sayangnya, Java tidak terlalu bagus dalam mengekspresikan tipe-tipe data tersebut.

peq
sumber
-2

Alih-alih lakukan sesuatu seperti ini

   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
    }

    }
onkar
sumber
4
Anda baru saja membuat fungsi pribadi yang dibungkus oleh fungsi publik. Mengapa tidak menerapkan ini saja di fungsi publik?
Martin Ueding
5
Dan Anda belum mengurangi jumlah pernyataan if.
Chad