将两个给定数组对配对并赢得大多数比较的最佳策略

问题描述 投票:0回答:2

我正在执行以下编程练习:Can you win the codewar?。该语句是:

Two kingdoms are at war ⚔️ and, thanks to your codewarrior prowesses, you have been named general by one of the warring states. Your opponent's armies are larger than yours, but maybe you can reach a stalemate or even win the conflict if you are a good strategist.

You control the same number of armies as the rival state, but theirs are generally larger. You have to send a single army to fight each of your opponent's ones.
(It implies there will be as many battles as armies).
There are no possible David-and-Goliath surprises : the outcome of a battle is always the victory of the larger army (or a standoff if both are of the same size).
The winning side is the one which wins the most battles.
The outcome can be a stalemate if both win the same number.

You have to write a function

codewarResult(codewarrior, opponent)

that takes as input each side's armies as arrays of positive integers which represent their sizes. The function returns the strings "Defeat" , "Stalemate" or "Victory" depending on the outcome of the war for your side with an optimal strategy on your behalf.

For example, if you have 3 armies of sizes [1,4,1] and the rival state has armies of sizes [1,5,3] , despite you having on average smaller forces, it is possible to reach a stalemate :

1-1 : standoff
4-3 : victory for you
1-5 : victory for the opposing army

when the dust settles, you have won one battle, lost one, and one was indecisive so

codewarResult([1,4,1],[1,5,3])

should return "Stalemate".
More examples :

codewarResult([2,4,3,1],[4,5,1,2])

should return "Victory" because it is possible to win by disposing your amies this way :

2-1
4-4
3-2
1-5

thus winning two battles, deadlocking one and losing one.

codewarResult([1,2,2,1],[3,1,2,3])

should return "Defeat" because even with an optimal strategy it is not possible to win. The best you can do is one victory and one tie :

1-3
2-1
2-2
1-3

我尝试了以下算法:

import java.util.*;
public class Kata {
  public static String codewarResult(int[] codewarrior, int[] opponent) {
    System.out.println("codewarrior: "+Arrays.toString(codewarrior));
    System.out.println("opponent: "+Arrays.toString(opponent));

    List<Integer> opponentMatchedIndexes = new ArrayList<Integer>();
    int closestTo1 = Integer.MIN_VALUE;
    int indexInCodewarrior = 0;
    int indexInOpponent = 0;
    int score = 0;
    int battleResult = 0;

    for(int i = 0; i < codewarrior.length; i++){
      closestTo1 = Integer.MIN_VALUE;
      indexInCodewarrior = 0;
      indexInOpponent = 0;
      for(int j = 0; j < opponent.length; j++){
        battleResult = codewarrior[i]-opponent[j];
        if(!opponentMatchedIndexes.contains(j) && battleResult>closestTo1 && battleResult<=1){
          closestTo1 = battleResult;
          indexInCodewarrior = i;
          indexInOpponent = j;
        }
      }
      score+=closestTo1 < 0 ? -1 : closestTo1 == 0 ? 0 : 1;
      opponentMatchedIndexes.add(indexInOpponent);

      System.out.println("closesTo1: "+closestTo1);
      System.out.println("indexInCodewarrior: "+indexInCodewarrior);
      System.out.println("indexInOpponent: "+indexInOpponent);
      System.out.println("NumberInCodewarrior: "+codewarrior[indexInCodewarrior]);
      System.out.println("NumberInOpponent: "+opponent[indexInOpponent]);
      System.out.println("opponentMatchedIndexes: "+opponentMatchedIndexes);
      System.out.println("score: "+score);
    }

    return score<0?"Defeat":score==0?"Stalemate":"Victory";
  }
}

[我们发现了一个测试,在应该输出“胜利”的情况下输出“僵局”:

@Test
public void testRandom() {
        int[] codewarrior = {2,5,1,4,1};
        int[] opponent =    {2,4,1,1,8};
    System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
    assertEquals("Victory", Kata.codewarResult(codewarrior, opponent));
}

我们已经写了应该做的代码:

2-1 = 1 --> score = 1; 5-4 = 1 --> score = 2; 1-1 = 0 --> score = 2; 4-2 = 2 --> score = 3; 1-8 = -7 --> score = 2

而且我们已经输入了正在执行的代码:

2-1 = 1 --> score = 1; 5-4 = 1 --> score = 2; 1-1 = 0 --> score = 2; 4-8 = -4 --> score = 1; 1-8=-7 --> score = 0

您在第4步中会注意到,它应该做4-2 = 2->分数= 3;但是它确实是4-8 = -4->得分= 1。

我们已经确定了应该更改代码的行,并且我们也考虑了需要更改的内容,但是我们很难弄清楚我们到底需要多少更改!

特别是我们需要更改以下代码行:

if(!opponentMatchedIndexes.contains(j) && battleResult>closestTo1 && battleResult<=1){

因为BattleResult <= 1在需要取4-2 = 2时限制了我们的算法,并且解释是由于是BattleResult = 2> 1,它只是跳过了保存数字的指令,如果。

此外,我们已阅读:

Math.max and Math.min outputting highest and lowest values allowedget closest value to a number in array

此外,我们如何调试大型测试?我的意思是,以下测试也失败了,但是由于输入数组的大小较大,因此很难弄清发生了什么:

@Test
public void testNumerousArmies() {
        int[] codewarrior = {2,1,3,1,1,3,3,2,3,1,1,1,3,1,3,1,3,3,1,2,3,3,1,3};
        int[] opponent =    {4,4,1,4,3,1,4,4,3,2,1,2,1,3,3,1,4,4,3,2,3,2,4,1};
    System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
    assertEquals("Stalemate", Kata.codewarResult(codewarrior, opponent));
}

如果您感到好奇,则完整的测试套件为:

import java.util.Arrays;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

// TODO: Replace examples and use TDD development by writing your own tests

public class SolutionTest {
    @Test
    public void testStalemate() {
            int[] codewarrior = {1,4,1};
            int[] opponent =    {1,5,3};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Stalemate", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testVictory() {
            int[] codewarrior = {2,4,3,1};
            int[] opponent =    {4,5,1,2};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Victory", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testDefeat() {
            int[] codewarrior = {1,2,2,1};
            int[] opponent =    {3,1,2,3};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Defeat", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testEqualArmies() {
            int[] codewarrior = {1,1,1,1};
            int[] opponent =    {1,1,1,1};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Stalemate", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testSingleArmy() {
            int[] codewarrior = {5};
            int[] opponent =    {6};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Defeat", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testNumerousArmies() {
            int[] codewarrior = {2,1,3,1,1,3,3,2,3,1,1,1,3,1,3,1,3,3,1,2,3,3,1,3};
            int[] opponent =    {4,4,1,4,3,1,4,4,3,2,1,2,1,3,3,1,4,4,3,2,3,2,4,1};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Stalemate", Kata.codewarResult(codewarrior, opponent));
    }


    @Test
    public void testRandom() {
            int[] codewarrior = {2,5,1,4,1};
            int[] opponent =    {2,4,1,1,8};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Victory", Kata.codewarResult(codewarrior, opponent));
    }
}

我们如何编写最佳策略来配对两个给定数组的对,并赢得大多数比较?

java arrays algorithm if-statement conditional-statements
2个回答
0
投票

首先,您需要根据战斗强度对阵列进行排序。从您比较的最高点开始。

  1. 如果您无法赢得战斗,您将以最低的力量对抗它。
  2. 如果是僵持。您现在有2个选项。让它成为僵局,或放松争取他人的战斗。因此,现在您将更深入并测试结果,看看您赢得最多的地方。

示例:

codewarChallenge([2,4,3,1],[4,5,1,2])

按顺序放置:([[1,2,3,4],[1,2,4,5])

4-5,您会放松,所以玩1-5。现在您已经离开([2,3,4],[1,2,4])

4-4对峙。两个选项4-4或2-4。

[当您打出4-4时,您剩下([2,3],[1,2]),您将同时赢得双赢]

[当您玩2-4时,您还剩下([3,4],[1,2]),您将赢得双赢

所以4-4是更好的选择。

您将需要使用递归模式。使一个函数接受两个数组并给出分数作为返回值。 0表示损失,1表示对峙,2表示获胜。现在在遇到僵局时递归调用该函数,以获取两个选项的其余分数。最高分获胜。

我受到Madjosz's exercise solution的启发。 (我看到了,在笔记本中写了它的伪代码,然后尝试将其转换为Java)。

它显示了我们如何完成练习,知道如果我们以升序排序,那么我们可以识别出胜利,然后我们应该能够检测到平局。这样我们就可以得到分数。

import java.util.*;
import java.util.stream.*;

public class Kata {

  public static String codewarResult/*⚔️🛡️*/(int[] codewarrior, int[] opponent) {

    //We sort both arrays according to battle strenght, in ascending order
    int battles = codewarrior.length;
    Arrays.sort(codewarrior);
    System.out.println("sorted codewarrior: "+Arrays.toString(codewarrior));
    Arrays.sort(opponent);
    System.out.println("sorted opponent: "+Arrays.toString(opponent));
    boolean[] CWusedElements = new boolean[battles];
    boolean[] OPusedElements = new boolean[battles];
    int wins = 0;
    int draws = 0;

    //We detect when we win
    for(int i = 0; i < battles; i++){
      int found = -1;
      for(int j = 0; j < battles; j++){
        if (OPusedElements[j]) continue;
        if (opponent[j] < codewarrior[i]) {
          found = j;
        }
        else break;
      }
      if(found!=-1){
        wins++;
        CWusedElements[i] = OPusedElements[found] = true;
        System.out.println("codewarrior[i]: "+codewarrior[i]);
        System.out.println("Win! opponent[found]: "+opponent[found]);
      }
    }

    //We know when we draw
    for(int i = 0; i < battles; i++){
      if(CWusedElements[i]) continue;
      int found = -1;
      for(int j = 0; j < battles; j++){
        if(OPusedElements[j]) continue;
        if(opponent[j] == codewarrior[i]) {
          found = j;
        }
        else break;
      }
      if(found!=-1){
        draws++;
        CWusedElements[i] = OPusedElements[found] = true;
        System.out.println("codewarrior[i]: "+codewarrior[i]);
        System.out.println("Draw, opponent[found]: "+opponent[found]);
      }
    }  

    System.out.println("CWusedElements: "+Arrays.toString(CWusedElements));
    int defeats = battles-draws-wins;
    int score = wins-defeats;
    System.out.println("defeats: "+defeats);
    System.out.println("wins: "+wins);
    System.out.println("draws: "+draws);
    System.out.println("battles: "+battles);
    System.out.println("score: "+score);
    return score>0?"Victory":score==0?"Stalemate":"Defeat";
  }
}

如果我们测试僵局,胜利和失败,如下:

import java.util.Arrays;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

// TODO: Replace examples and use TDD development by writing your own tests

public class SolutionTest {
    @Test
    public void testStalemate() {
            int[] codewarrior = {1,4,1};
            int[] opponent =    {1,5,3};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Stalemate", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testVictory() {
            int[] codewarrior = {2,4,3,1};
            int[] opponent =    {4,5,1,2};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Victory", Kata.codewarResult(codewarrior, opponent));
    }

    @Test
    public void testDefeat() {
            int[] codewarrior = {1,2,2,1};
            int[] opponent =    {3,1,2,3};
        System.out.println(Arrays.toString(codewarrior)+" vs "+Arrays.toString(opponent));
        assertEquals("Defeat", Kata.codewarResult(codewarrior, opponent));
    }
}

跟踪将是:

[1, 4, 1] vs [1, 5, 3]
sorted codewarrior: [1, 1, 4]
sorted opponent: [1, 3, 5]
codewarrior[i]: 4
Win! opponent[found]: 3
codewarrior[i]: 1
Draw, opponent[found]: 1
CWusedElements: [true, false, true]
defeats: 1
wins: 1
draws: 1
battles: 3
score: 0

[2, 4, 3, 1] vs [4, 5, 1, 2]
sorted codewarrior: [1, 2, 3, 4]
sorted opponent: [1, 2, 4, 5]
codewarrior[i]: 2
Win! opponent[found]: 1
codewarrior[i]: 3
Win! opponent[found]: 2
codewarrior[i]: 4
Draw, opponent[found]: 4
CWusedElements: [false, true, true, true]
defeats: 1
wins: 2
draws: 1
battles: 4
score: 1

[1, 2, 2, 1] vs [3, 1, 2, 3]
sorted codewarrior: [1, 1, 2, 2]
sorted opponent: [1, 2, 3, 3]
codewarrior[i]: 2
Win! opponent[found]: 1
codewarrior[i]: 2
Draw, opponent[found]: 2
CWusedElements: [false, false, true, true]
defeats: 2
wins: 1
draws: 1
battles: 4
score: -1

0
投票

我受到Madjosz's exercise solution的启发。 (我看到了,在笔记本中写了它的伪代码,然后尝试将其转换为Java)。

© www.soinside.com 2019 - 2024. All rights reserved.