The following code does work how I need it to, but it\'s ugly, excessive or a number of other things. I\'ve looked at formulas and attempted to write a few solutions, but I
Since you prefer nested if
conditionals , here's another way.
Note that it doesn't use the result
member and it doesn't change any state.
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;
}
I hope I understand the logic correctly. How about something like:
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;
}
Checking one hit high or one hit low is not blocked and the same for player two.
Edit: Algorithm was not fully understood, "hit" awarded when blocking which I did not realize (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;
}
Since your data set is so small, you can compress everything into 1 long integer and turn it into a formula
public int fightMath(int one,int two)
{
return (int)(0xF9F66090L >> (2*(one*4 + two)))%4;
}
This makes use of the fact everything is a multiple of 2
public int fightMath(int one,int two)
{
return (0xF9F66090 >> ((one << 3) | (two << 1))) & 0x3;
}
What can I say? The world needs magic, sometimes the possibility of something calls for its creation.
The essence of the function that solves OP's problem is a map from 2 numbers (one,two), domain {0,1,2,3} to the range {0,1,2,3}. Each of the answers has approached how to implement that map.
Also, you can see in a number of the answers a restatement of the problem as a map of 1 2-digit base 4 number N(one,two) where one is digit 1, two is digit 2, and N = 4*one + two; N = {0,1,2,...,15} -- sixteen different values, that's important. The output of the function is one 1-digit base 4 number {0,1,2,3} -- 4 different values, also important.
Now, a 1-digit base 4 number can be expressed as a 2-digit base 2 number; {0,1,2,3} = {00,01,10,11}, and so each output can be encoded with only 2 bits. From above, there are only 16 different outputs possible, so 16*2 = 32 bits is all that is necessary to encode the entire map; this can all fit into 1 integer.
The constant M is an encoding of the map m where m(0) is encoded in bits M[0:1], m(1) is encoded in bits M[2:3], and m(n) is encoded in bits M[n*2:n*2+1].
All that remains is indexing and returning the right part of the constant, in this case you can shift M right 2*N times and take the 2 least significant bits, that is (M >> 2*N) & 0x3. The expressions (one << 3) and (two << 1) are just multiplying things out while noting that 2*x = x << 1 and 8*x = x << 3.
Why not use an array?
I will start from the beginning. I see a pattern, the values goes from 0 to 3 and you want catch all possible values. This is your table:
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
when we look at this same table binary we see the following results:
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
Now maybe you already see some pattern but when I combine value one and two I see that you're using all values 0000, 0001, 0010,..... 1110 and 1111. Now let's combine value one and two to make a single 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
When we translate this back into decimal values we see an very possible array of values where the one and two combined could be used as index:
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
The array is then {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3}
, where it's index is simply one and two combined.
I'm not a Java programmer but you can get rid of all if statements and just write it down as something like this:
int[] myIntArray = {0, 0, 1, 2, 0, 0, 2, 1, 2, 1, 3, 3, 2, 1, 3, 3};
result = myIntArray[one * 4 + two];
I don't know if a bitshift by 2 is faster than multiplication. But it could be worth a try.
I don't have experience with Java so there might be some typos. Please consider the code as pseudo-code.
I'd go with a simple switch. For that, you'd need a single number evaluation. However, for this case, since 0 <= one < 4 <= 9
and 0 <= two < 4 <= 9
, we can convert both ints to a simple int by multiplying one
by 10 and adding two
. Then use a switch in the resulting number like this:
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;
}
There's another short method that I just want to point out as a theoretical code. However I wouldn't use it because it has some extra complexity that you don't normally want to deal with. The extra complexity comes from the base 4, because the counting is 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];
}
Really just additional note, in case I'm missing something from Java. In PHP I'd do:
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];
}
I'd use a Map, either a HashMap or a TreeMap
Especially if the parameters are not on the form 0 <= X < N
Like a set of random positive integers ..
Code
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);
}
}