我受到Madjosz's exercise solution的启发。 (我看到了,在笔记本中写了它的伪代码,然后尝试将其转换为Java)。
我正在执行以下编程练习: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));
}
}
我们如何编写最佳策略来配对两个给定数组的对,并赢得大多数比较?
首先,您需要根据战斗强度对阵列进行排序。从您比较的最高点开始。
示例:
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
我受到Madjosz's exercise solution的启发。 (我看到了,在笔记本中写了它的伪代码,然后尝试将其转换为Java)。