I am doing the following programming exercise: Can you win the codewar?. The statement is:
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
I have tried the following algorithm:
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";
}
}
We have found a test where it outputs "Stalemate" when it should output "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));
}
We have written what should do the code:
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
And we have typed what is doing the code right now:
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
As you would notice at the 4th step it should do 4-2 = 2 --> score = 3; however it does 4-8=-4 --> score = 1.
We have spotted the line where we should change the code, and we have also thought what needs to be changed, however we struggle figuring out how exactly do we need to change it!
In particular we need to change the following line of code:
if(!opponentMatchedIndexes.contains(j) && battleResult>closestTo1 && battleResult<=1){
Because of battleResult<=1 is limiting our algorithm when it needs to take 4-2 = 2, and the explanation is that due to being battleResult = 2 > 1, it just skips out the instructions to save the number, inside the if.
In addition we have read:
Math.max and Math.min outputting highest and lowest values allowed get closest value to a number in array
Besides, how could we debug larger tests? I mean, the following tests also fails, however due to its bigger input arrays' size it is harder to figure out what is it happening:
@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));
}
If you are curious the complete test suite is:
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));
}
}
How could we write an Optimal strategy to pair pairs of two given arrays, and win most of the comparisons?
Aucun commentaire:
Enregistrer un commentaire