Za dużo stwierdzeń "jeśli"?

Poniższy kod działa tak, jak go potrzebuję, ale jest brzydki, nadmierny lub wiele innych rzeczy. Spojrzałem na formuły i próbowałem napisać kilka rozwiązań, ale kończę z podobną ilością stwierdzeń.

Czy Jest jakiś wzór matematyczny, który by mi się przydał w tym przypadku, czy jest 16, jeśli wyrażenia są akceptowalne?

Aby wyjaśnić kod, jest to rodzaj symultanicznej gry turowej.. dwóch graczy ma po cztery przyciski akcji. wyniki pochodzą z tablicy (0-3), ale zmienne "jeden" i " dwa " mogą być przypisane cokolwiek, jeśli to pomoże. Wynik: 0 = Żadna wygrana, 1 = p1 wygrana, 2 = P2 wygrana, 3 = obie wygrane.

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;
}
Author: TomFirth, 2014-03-19

26 answers

Jeśli nie możesz wymyślić formuły, możesz użyć tabeli dla tak ograniczonej liczby wyników:

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];
 600
Author: laalto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 22:52:56

Ponieważ twój zestaw danych jest tak mały, możesz skompresować wszystko do 1 długiej liczby całkowitej i przekształcić ją w Formułę

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

Bardziej bitowy wariant:

To wykorzystuje fakt, że wszystko jest wielokrotnością 2

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

Pochodzenie magicznej stałej

Cóż mogę powiedzieć? Świat potrzebuje magii, czasem możliwość czegoś wymaga jego stworzenia.

Istotą funkcji rozwiązującej problem OP jest mapa z 2 liczb (jedna,dwie), domena {0,1,2,3} do zakresu {0,1,2,3}. Każda z odpowiedzi podchodziła do tego, jak zaimplementować tę mapę.

Również, można zobaczyć w liczbie odpowiedzi ponowne określenie problemu jako mapę 1 2-cyfrowej bazy 4 liczba N (jeden, dwa), gdzie jeden jest cyfra 1, dwa jest cyfra 2, I N = 4*jeden + dwa; n = {0,1,2,...Szesnaście różnych wartości, to ważne. Wyjście funkcji to jedna 1-Cyfrowa Baza 4 liczba {0,1,2,3} -- 4 różne wartości, również ważne.

Teraz, 1-Cyfrowa Baza 4 liczba może być wyrażona jako 2-cyfrowa liczba podstawowa 2; {0,1,2,3} = {00,01,10,11}, a więc każde wyjście może być zakodowane tylko 2 bitami. Z góry możliwe jest tylko 16 różnych wyjść, więc 16*2 = 32 bity to wszystko, co jest niezbędne do zakodowania całej mapy; to wszystko może zmieścić się w 1 liczbie całkowitej.

Stała M jest kodowaniem mapy m, gdzie m(0) jest kodowane w bitach M[0:1], m (1) jest kodowane w bitach m [2:3], A M (n) jest kodowane w bitach M[n*2:n*2+1].

Pozostaje tylko indeksowanie i zwracając prawą część stałej, w tym przypadku można przesunąć M w prawo 2 * N razy i wziąć 2 najmniej znaczące bity, czyli (M >> 2*N) & 0x3. Wyrażenia (jeden

 201
Author: waTeim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 21:08:56

Nie podoba mi się żadne z prezentowanych rozwiązań poza JAB ' s. żadne z pozostałych nie ułatwia odczytania kodu i zrozumienia, co jest obliczane .

Oto jak napisałbym ten kod -- znam tylko C#, a nie Javę, ale macie obrazek:

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

Teraz jest o wiele bardziej jasne, co jest tutaj obliczane: to podkreśla, że obliczamy, kto zostanie uderzony przez jaki atak, i zwracamy oba wyniki.

Jednak może być jeszcze lepiej; że Boolean tablica jest nieco nieprzezroczysta. Podoba mi się podejście do wyszukiwania tabeli, ale byłbym skłonny napisać go w taki sposób, że jasno, co zamierzona semantyka gry były. Oznacza to, że zamiast" atak zerowy i obrona jednego powoduje brak trafienia", zamiast tego znajdź sposób, aby Kod wyraźniej implikował "atak low kick i obrona low block powoduje brak trafienia". aby Kod odzwierciedlał logikę biznesową gry.

 98
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-28 15:31:13

Można utworzyć macierz zawierającą wyniki

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

Gdy chcesz uzyskać wartość, użyj

public int fightMath(int one, int two) {
  return this.results[one][two]; 
}
 87
Author: djm.im,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 09:02:25

Inni ludzie już zasugerowali mój początkowy pomysł, metodę matrix, ale oprócz konsolidacji instrukcji if możesz uniknąć niektórych z tego, co masz, upewniając się, że podane argumenty są w oczekiwanym zakresie i używając zwrotów in-place (niektóre standardy kodowania, które widziałem, wymuszają jeden punkt wyjścia dla funkcji, ale odkryłem, że wiele zwrotów jest bardzo przydatnych do unikania kodowania strzałek i z powszechnością WYJĄTKÓW w Javie nie ma zbyt wiele sensu w stricte egzekwowanie takiej reguły tak, jak każdy nieobciążony wyjątek wrzucony wewnątrz metody jest możliwym punktem wyjścia). Zagnieżdżanie poleceń switch jest możliwe, ale dla małego zakresu wartości, które tutaj sprawdzasz, stwierdzam, czy polecenia są bardziej kompaktowe i prawdopodobnie nie spowodują dużej różnicy wydajności, zwłaszcza jeśli twój program jest turowy, a nie w czasie rzeczywistym.

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
}

Jest to mniej czytelne, niż mogłoby to wynikać z nieregularności części danych wejściowych - > mapowanie wyników. W przeciwieństwie do poprzednich wersji, matrix został zaprojektowany w taki sposób, aby można było go używać w dowolnym miejscu i czasie.]}

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

Update: biorąc pod uwagę twoją wzmiankę o blokowaniu / uderzaniu, tutaj jest bardziej radykalna zmiana funkcji, która wykorzystuje propertied / atrybut-holding wyliczone typy dla wejść i wyniku, a także modyfikuje wynik trochę, aby uwzględnić blokowanie, co powinno uzyskaj bardziej czytelną funkcję.

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

Nie musisz nawet zmieniać samej funkcji, jeśli chcesz dodać bloki/ataki o większej wysokości, tylko liczby; dodanie dodatkowych rodzajów ruchów prawdopodobnie będzie wymagało modyfikacji funkcji. Również, EnumSets może być bardziej rozszerzalne niż używanie dodatkowych enum jako właściwości głównego enum, np. EnumSet<Move> attacks = EnumSet.of(Move.ATTACK_HIGH, Move.ATTACK_LOW, ...); i wtedy attacks.contains(move) zamiast move.type == MoveType.ATTACK, chociaż użycie EnumSet S będzie prawdopodobnie nieco wolniejsze niż bezpośrednie równe czeki.


W przypadku, gdy pomyślny blok powoduje licznik, można zastąpić if (one.height == two.height) return LandedHit.NEITHER; przez

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

Również zastąpienie niektórych instrukcji if operatorem trójdzielnym (boolean_expression ? result_if_true : result_if_false) może sprawić, że kod będzie bardziej zwarty (na przykład kod w poprzednim bloku stanie się return one.isAttack() ? LandedHit.PLAYER_TWO : LandedHit.PLAYER_ONE;), ale może to prowadzić do trudniejszego do odczytania jednego z nich, więc nie polecałbym go do bardziej skomplikowanego rozgałęzienia.

 69
Author: JAB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 13:11:53

Dlaczego nie użyć tablicy?

Zacznę od początku. Widzę wzór, wartości idzie od 0 do 3 i chcesz złapać wszystkie możliwe wartości. To jest twoja Tabela:
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

Patrząc na tę samą tabelę widzimy następujące wyniki:

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

Teraz może już widzisz jakiś wzorzec, ale kiedy połączę wartość 1 i 2 widzę, że używasz wszystkich wartości 0000, 0001, 0010,..... 1110 i 1111. Teraz połączmy wartość 1 i 2, aby utworzyć pojedynczy 4 bit liczba całkowita.

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

Kiedy przetłumaczymy to z powrotem na wartości dziesiętne, widzimy bardzo możliwą tablicę wartości, w której jedna i dwie połączone mogą być użyte jako 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

Tablica jest wtedy {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3}, gdzie indeks jest po prostu jeden i dwa połączone.

Nie jestem programistą Javy, ale możesz pozbyć się wszystkich stwierdzeń if I po prostu zapisać je jako coś takiego:

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

Nie wiem, czy bitshift przez 2 jest szybszy niż mnożenie. Ale warto spróbować.

 50
Author: dj bazzie wazzie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-28 20:19:22

To używa trochę bitmagic (już to robisz, trzymając dwa bity informacji (niski / wysoki & atak/blok) w jednej liczbie całkowitej):

nie uruchomiłem go, tylko wpisałem tutaj, proszę.Pomysł na pewno działa. EDIT: {[7] } jest teraz testowany dla każdego wejścia, działa dobrze.

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

Czy powinienem sugerować oddzielenie tych dwóch bitów informacji w osobne zmienne? Kod oparty głównie na takich operacjach bitowych jak ta powyżej jest zazwyczaj bardzo trudny do utrzymać.

 24
Author: elias,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 22:26:37

Szczerze mówiąc, każdy ma swój własny styl kodu. Nie przypuszczałbym, że wydajność będzie miała zbyt duży wpływ. Jeśli rozumiesz to lepiej niż użycie wersji obudowy przełącznika, kontynuuj korzystanie z tego.

Możesz zagnieżdżać if, więc potencjalnie może wystąpić nieznaczny wzrost wydajności w przypadku ostatnich kontroli, ponieważ nie przeszłoby to tak wiele deklaracji if. Ale w kontekście podstawowego kursu java to prawdopodobnie nie przyniesie korzyści.

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

Więc zamiast z...

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; }
Zrobiłbyś to...
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; }
}

I po prostu sformatuj go tak, jak wolisz.

To nie sprawia, że kod wygląda lepiej, ale potencjalnie przyspiesza go trochę wierzę.

 20
Author: Joe Harper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 09:50:46

Zobaczmy, co wiemy

1: twoje odpowiedzi są symetryczne dla P1 (gracz pierwszy) i P2 (gracz drugi). To ma sens dla gry walki, ale jest również coś, co można wykorzystać do poprawy logiki.

2: 3 uderzeń 0 uderzeń 2 uderzeń 1 uderzeń 3. Jedynymi przypadkami, które nie są objęte tymi przypadkami, są kombinacje 0 vs 1 i 2 vs 3. Inaczej mówiąc, unikalna tabela zwycięstw wygląda tak: 0 uderzeń 2, 1 uderzeń 3, 2 uderzeń 1, 3 uderzeń 0.

3: Jeśli 0/1 pójdzie na przeciw siebie wtedy jest remis bez trafień ale jeśli 2/3 pójdzie do siebie to oba trafią

Najpierw zbudujmy funkcję jednokierunkową mówiącą nam, czy wygramy:

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

Możemy następnie użyć tej funkcji do skomponowania wyniku końcowego:

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

Chociaż jest to prawdopodobnie bardziej złożone i prawdopodobnie wolniejsze niż wyszukiwanie tabel oferowane w wielu odpowiedziach, uważam, że jest to lepsza metoda, ponieważ faktycznie zawiera logikę Twojego kodu i opisuje ją każdemu, kto czyta Twój kod. I myślę, że to sprawia, że jest to lepsze wdrożenie.

(minęło trochę czasu od kiedy zrobiłem jakąś Javę, więc przepraszam jeśli składnia jest wyłączona, mam nadzieję, że nadal jest zrozumiała, jeśli trochę się pomyliłem)

Przy okazji, 0-3 wyraźnie oznacza coś; nie są one dowolnymi wartościami, więc przydałoby się je nazwać.

 12
Author: Jack Aidley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 11:44:00

Mam nadzieję, że dobrze rozumiem logikę. A może coś w stylu:

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

Sprawdzanie jednego uderzenia wysokiego lub jednego uderzenia niskiego nie jest blokowane i to samo dla gracza drugiego.

Edit: algorytm nie był do końca zrozumiały," hit " przyznawany przy blokowaniu którego nie zdawałem sobie sprawy (Thx): {]}

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;
}
 11
Author: Chris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 19:49:01

Nie mam doświadczenia z Javą więc mogą być jakieś literówki. Proszę traktować kod jako pseudo-kod.

Wybrałbym prosty przełącznik. Do tego potrzebowałbyś jednej oceny liczby. Jednak w tym przypadku, ponieważ 0 <= one < 4 <= 9 i 0 <= two < 4 <= 9, możemy przekształcić oba Int do prostej int przez pomnożenie {[5] } przez 10 i dodanie two. Następnie użyj przełącznika w liczbie wynikowej w następujący sposób:
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;
}
Jest jeszcze jedna krótka metoda, którą chcę tylko wskazać jako teoretyczny kod. Jednak Ja nie używałbym go, ponieważ ma dodatkową złożoność, z którą normalnie nie chcesz sobie radzić. Dodatkowa złożoność pochodzi z bazy 4 , ponieważ liczenie jest 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];
}

Naprawdę tylko dodatkowa uwaga, na wypadek, gdybym coś przeoczył z Javy. W PHP zrobiłbym:

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];
}
 10
Author: Francisco Presencia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-08 20:51:00

Ponieważ wolisz zagnieżdżone if uwarunkowania, oto inny sposób.
Zauważ, że nie używa on elementu result i nie zmienia żadnego stanu.

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;
}
 7
Author: Nick Dandoulakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 18:42:28

Spróbuj z obudową przełącznika...

Zobacz tutaj lub tutaj aby uzyskać więcej informacji na ten temat

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

Możesz dodać do niego wiele warunków(nie jednocześnie), a nawet mieć domyślną opcję, gdzie inne przypadki nie zostały spełnione.

PS: tylko wtedy, gdy ma być spełniony jeden warunek..

Jeżeli jednocześnie powstają 2 warunki.. Nie sądzę, żeby można było użyć przełącznika. Ale możesz zmniejszyć kod proszę.

Instrukcja Java Switch multiple cases

 6
Author: Nevin Madhukar K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:14

Pierwszą rzeczą, która przyszła mi do głowy, była zasadniczo ta sama Odpowiedź udzielona przez Francisco Presencia, ale nieco zoptymalizowana:

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

Można go dodatkowo zoptymalizować, czyniąc ostatni przypadek (dla 3) domyślnym przypadkiem:

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

Zaletą tej metody jest to, że łatwiej jest zobaczyć, które wartości dla one i two odpowiadają którym wartościom zwrotnym niż niektóre z innych sugerowanych metod.

 6
Author: David R Tribble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 17:52:52
((two&2)*(1+((one^two)&1))+(one&2)*(2-((one^two)&1)))/2
 6
Author: Dawood ibn Kareem,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-21 08:04:10

Możesz użyć switch case zamiast mutiple if

Również wspomnieć, że ponieważ masz dwie zmienne, musisz połączyć dwie zmienne, aby użyć ich w switch

Sprawdź to Java switch aby obsłużyć dwie zmienne?

 4
Author: Rahul Tripathi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:11

Kiedy rysuję tabelę pomiędzy 1/2 a wynikiem, widzę jeden wzór,

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

Powyższe zmniejszyłoby co najmniej 3, Jeśli wypowiedzi. Nie widzę wzoru zestawu ani nie jestem w stanie wiele wyciągnąć z podanego kodu - ale jeśli taka logika może być wyprowadzona, to zmniejszyłoby to liczbę twierdzeń if.

Mam nadzieję, że to pomoże.
 3
Author: AnonNihcas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 09:44:58

Dobrym punktem byłoby zdefiniowanie reguł jako tekstu, wtedy łatwiej będzie uzyskać poprawną formułę. Jest to wyciągnięte z ładnej reprezentacji tablicy laalto:

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

I oto kilka ogólnych komentarzy, ale powinieneś opisać je w kategoriach reguł:

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

Możesz oczywiście ograniczyć to do mniejszego kodu, ale ogólnie dobrym pomysłem jest zrozumienie tego, co kodujesz, a nie znalezienie kompaktowego rozwiązania.

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

Jakieś wyjaśnienie skomplikowanego p1/p2 hity byłyby świetne, wygląda ciekawie!

 3
Author: Marcellus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 23:23:24

Najkrótsze i wciąż czytelne rozwiązanie:

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

Lub jeszcze krócej:

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

Nie zawiera żadnych "magicznych" liczb ;) Mam nadzieję, że to pomoże.

 3
Author: P.W.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 13:25:33

Ja osobiście lubię kaskadować operatory trójdzielne:

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

Ale w Twoim przypadku możesz użyć:

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

Lub, można zauważyć wzór w bitach:

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

Więc możesz używać magii:

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
Author: Kirill Gamazkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 20:06:28

Oto dość zwięzła wersja, podobna do odpowiedzi JAB . To wykorzystuje mapę do przechowywania, który przenosi triumf nad innymi.

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

Przykład:

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

Druki:

P1Win
 1
Author: Duncan Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:51

Użyłbym Mapy, HashMap lub TreeMap

Szczególnie jeśli parametry nie znajdują się na formularzu 0 <= X < N

Jak zbiór losowych dodatnich liczb całkowitych ..

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
Author: Khaled.K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-26 07:18:11

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

 1
Author: user1837841,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-04 01:21:26

Dzięki @ Joe Harper jak skończyło się na użyciu odmiany jego odpowiedź. Aby odchudzić go dalej, ponieważ wyniki 2 na 4 były takie same, odchudziłem go dalej.

Może kiedyś do tego wrócę, ale jeśli nie będzie większego oporu spowodowanego wieloma if-oświadczeniami, to zatrzymam to na razie. Przyjrzę się macierzy tabeli i dalej przełączam rozwiązania instrukcji.

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; }
  }
}
 1
Author: TomFirth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-02 10:25:41
  1. Użyj stałych lub enum, aby uczynić kod bardziej czytelnym
  2. spróbuj podzielić kod na więcej funkcji
  3. Spróbuj użyć symetrii problemu

Oto sugestia, jak to może wyglądać, ale używanie ints tutaj jest nadal trochę brzydkie:

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

Lepiej byłoby użyć typu strukturalnego dla wejścia i wyjścia. Wejście ma w rzeczywistości dwa pola: pozycję i typ (blok lub atak). Wyjście posiada również dwa pola: player1Wins oraz player2Wins. Kodowanie tego do jednej liczby całkowitej utrudnia odczytanie kodu.

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

Niestety, Java nie jest zbyt dobra w wyrażaniu tego rodzaju typów danych.

 0
Author: Peter Zeller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-29 18:03:48

Zamiast zrobić coś takiego

   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
    }

    }
 -2
Author: onkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-19 09:32:12