Problem
I am trying to code a little program which mimics the code wheel which was included in the computer game The Secret Of Monkey Island. It consists of two cardboard wheels with pirate faces on it. Combining the upper half of the face with another lower half shows different year dates in windows cut out of the second disk. You can see it here: Dial-A-Pirate
So far the task seems pretty straight forward for me. I have an array for my years and two array lists for the identifier of the images file names:
private int [][] years = { {1710, 1651, 1679, 1719, 1694, 1632, 1668, 1703, 1726, 1564, 1615, 1599, 1669, 1660, 1687},
{1658, 1702, 1725, 1630, 1709, 1594, 1614, 1563, 1649, 1693, 1577, 1678, 1686, 1597, 1718},
{1724, 1667, 1691, 1685, 1613, 1580, 1723, 1717, 1684, 1628, 1643, 1559, 1573, 1708, 1701},
{1672, 1562, 1721, 1666, 1673, 1670, 1692, 1656, 1567, 1674, 1662, 1655, 1646, 1671, 1611},
{1627, 1707, 1688, 1699, 1568, 1705, 1579, 1585, 1665, 1706, 1506, 1722, 1716, 1584, 1551},
{1566, 1592, 1654, 1635, 1639, 1695, 1704, 1711, 1609, 1681, 1712, 1542, 1565, 1720, 1664},
{1690, 1682, 1601, 1619, 1680, 1621, 1652, 1689, 1713, 1697, 1696, 1624, 1604, 1653, 1641}};
ArrayList<Integer> disk1 = new ArrayList<Integer>();
ArrayList<Integer> disk2 = new ArrayList<Integer>();
public void createDisks() {
int i;
for(i=1; i <=29; i = i +2 ){
disk1.add(i);
}
for(i=2; i <=30; i = i +2 ){
disk2.add(i);
}
}
I use collections.rotate to rotate my lists by one and am only looking at position [0] [0]
.
Since there are only really 15 different combinations of the wheel I created an int pirateID to set the labels to the corresponding years in the arrays.
And this lead me to my question. The only possible way of doing that I came up with is a huge if
statement:
private int getPirateID() {
String temp = Integer.toString(disk1.get(0)) + Integer.toString(disk2.get(0));
pirateID = Integer.parseInt(temp);
if (pirateID == 12 || pirateID == 34 || pirateID == 56 || pirateID == 78 || pirateID == 910 || pirateID == 1112 || pirateID == 1314 || pirateID == 1516 || pirateID == 1718 || pirateID == 1920 || pirateID == 2122 || pirateID == 2324 || pirateID == 2526 || pirateID == 2728 || pirateID == 2930) {
pirateID = 0;
}
if (pirateID == 130 || pirateID == 32 || pirateID == 54 || pirateID == 76 || pirateID == 98 || pirateID == 1110 || pirateID == 1312 || pirateID == 1514 || pirateID == 1716 || pirateID == 1918 || pirateID == 2120 || pirateID == 2322 || pirateID == 2524 || pirateID == 2726 || pirateID == 2928) {
pirateID = 1;
}
if (pirateID == 128 || pirateID == 330 || pirateID == 52 || pirateID == 74 || pirateID == 96 || pirateID == 118 || pirateID == 1310 || pirateID == 1512 || pirateID == 1714 || pirateID == 1916 || pirateID == 2118 || pirateID == 2320 || pirateID == 2522 || pirateID == 2724 || pirateID == 2926) {
pirateID = 2;
}
if (pirateID == 126 || pirateID == 328 || pirateID == 530 || pirateID == 72 || pirateID == 94 || pirateID == 116 || pirateID == 138 || pirateID == 1510 || pirateID == 1712 || pirateID == 1914 || pirateID == 2116 || pirateID == 2318 || pirateID == 2520 || pirateID == 2722 || pirateID == 2924) {
pirateID = 3;
}
if (pirateID == 124 || pirateID == 326 || pirateID == 528 || pirateID == 730 || pirateID == 92 || pirateID == 114 || pirateID == 136 || pirateID == 158 || pirateID == 1710 || pirateID == 1912 || pirateID == 2114 || pirateID == 2316 || pirateID == 2518 || pirateID == 2720 || pirateID == 2922) {
pirateID = 4;
}
if (pirateID == 122 || pirateID == 324 || pirateID == 526 || pirateID == 728 || pirateID == 930 || pirateID == 112 || pirateID == 134 || pirateID == 156 || pirateID == 178 || pirateID == 1910 || pirateID == 2112 || pirateID == 2314 || pirateID == 2516 || pirateID == 2718 || pirateID == 2920) {
pirateID = 5;
}
if (pirateID == 120 || pirateID == 322 || pirateID == 524 || pirateID == 726 || pirateID == 928 || pirateID == 1130 || pirateID == 132 || pirateID == 154 || pirateID == 176 || pirateID == 198 || pirateID == 2110 || pirateID == 2312 || pirateID == 2514 || pirateID == 2716 || pirateID == 2918) {
pirateID = 6;
}
if (pirateID == 118 || pirateID == 320 || pirateID == 522 || pirateID == 724 || pirateID == 926 || pirateID == 1128 || pirateID == 1330 || pirateID == 152 || pirateID == 174 || pirateID == 196 || pirateID == 218 || pirateID == 2310 || pirateID == 2512 || pirateID == 2714 || pirateID == 2916) {
pirateID = 7;
}
if (pirateID == 116 || pirateID == 318 || pirateID == 520 || pirateID == 722 || pirateID == 924 || pirateID == 1126 || pirateID == 1328 || pirateID == 1530 || pirateID == 172 || pirateID == 194 || pirateID == 216 || pirateID == 238 || pirateID == 2510 || pirateID == 2712 || pirateID == 2914) {
pirateID = 8;
}
if (pirateID == 114 || pirateID == 316 || pirateID == 518 || pirateID == 720 || pirateID == 922 || pirateID == 1124 || pirateID == 1326 || pirateID == 1528 || pirateID == 1730 || pirateID == 192 || pirateID == 214 || pirateID == 236 || pirateID == 258 || pirateID == 2710 || pirateID == 2912) {
pirateID = 9;
}
if (pirateID == 112 || pirateID == 314 || pirateID == 516 || pirateID == 718 || pirateID == 920 || pirateID == 1122 || pirateID == 1324 || pirateID == 1526 || pirateID == 1728 || pirateID == 1930 || pirateID == 212 || pirateID == 234 || pirateID == 256 || pirateID == 278 || pirateID == 2910) {
pirateID = 10;
}
if (pirateID == 110 || pirateID == 312 || pirateID == 514 || pirateID == 716 || pirateID == 918 || pirateID == 1120 || pirateID == 1322 || pirateID == 1524 || pirateID == 1726 || pirateID == 1928 || pirateID == 2130 || pirateID == 232 || pirateID == 254 || pirateID == 276 || pirateID == 298) {
pirateID = 11;
}
if (pirateID == 18 || pirateID == 310 || pirateID == 512 || pirateID == 714 || pirateID == 916 || pirateID == 1118 || pirateID == 1320 || pirateID == 1522 || pirateID == 1724 || pirateID == 1926 || pirateID == 2128 || pirateID == 2330 || pirateID == 252 || pirateID == 274 || pirateID == 296) {
pirateID = 12;
}
if (pirateID == 16 || pirateID == 38 || pirateID == 510 || pirateID == 712 || pirateID == 914 || pirateID == 1116 || pirateID == 1318 || pirateID == 1520 || pirateID == 1722 || pirateID == 1924 || pirateID == 2126 || pirateID == 2328 || pirateID == 2530 || pirateID == 272 || pirateID == 294) {
pirateID = 13;
}
if (pirateID == 14 || pirateID == 36 || pirateID == 58 || pirateID == 710 || pirateID == 912 || pirateID == 1114 || pirateID == 1316 || pirateID == 1518 || pirateID == 1720 || pirateID == 1922 || pirateID == 2124 || pirateID == 2326 || pirateID == 2528 || pirateID == 2730 || pirateID == 292) {
pirateID = 14;
}
return pirateID;
}
But that really can’t be it. There has to be a much shorter way of doing this, right?
Solution
There is only one real variable, which is the ‘innerDiskOffset’. Try to express all the other variables as function of this ‘innerDiskOffset’. There are only 15 offsets, so you can code this in an array or list.
I would create a mapping, using a 2-dimensional array (or list might work as well).
I admit it has been many years since I did much Java so I am a bit rusty but I was able to come up with the code below.
First, I made a method to return the mapping:
private int[][] getMapping() {
int[][] mapping = {
{ 12 , 34 , 56 , 78 , 910 , 1112 , 1314 , 1516 , 1718 , 1920 , 2122 , 2324 , 2526 , 2728 , 2930 },
{ 130 , 32 , 54 , 76 , 98 , 1110 , 1312 , 1514 , 1716 , 1918 , 2120 , 2322 , 2524 , 2726 , 2928 },
{ 128 , 330 , 52 , 74 , 96 , 118 , 1310 , 1512 , 1714 , 1916 , 2118 , 2320 , 2522 , 2724 , 2926 },
{ 126 , 328 , 530 , 72 , 94 , 116 , 138 , 1510 , 1712 , 1914 , 2116 , 2318 , 2520 , 2722 , 2924 },
{ 124 , 326 , 528 , 730 , 92 , 114 , 136 , 158 , 1710 , 1912 , 2114 , 2316 , 2518 , 2720 , 2922 },
{ 122 , 324 , 526 , 728 , 930 , 112 , 134 , 156 , 178 , 1910 , 2112 , 2314 , 2516 , 2718 , 2920 },
{ 120 , 322 , 524 , 726 , 928 , 1130 , 132 , 154 , 176 , 198 , 2110 , 2312 , 2514 , 2716 , 2918 },
{ 118 , 320 , 522 , 724 , 926 , 1128 , 1330 , 152 , 174 , 196 , 218 , 2310 , 2512 , 2714 , 2916 },
{ 116 , 318 , 520 , 722 , 924 , 1126 , 1328 , 1530 , 172 , 194 , 216 , 238 , 2510 , 2712 , 2914 },
{ 114 , 316 , 518 , 720 , 922 , 1124 , 1326 , 1528 , 1730 , 192 , 214 , 236 , 258 , 2710 , 2912 },
{ 112 , 314 , 516 , 718 , 920 , 1122 , 1324 , 1526 , 1728 , 1930 , 212 , 234 , 256 , 278 , 2910 },
{ 110 , 312 , 514 , 716 , 918 , 1120 , 1322 , 1524 , 1726 , 1928 , 2130 , 232 , 254 , 276 , 298 },
{ 18 , 310 , 512 , 714 , 916 , 1118 , 1320 , 1522 , 1724 , 1926 , 2128 , 2330 , 252 , 274 , 296 },
{ 16 , 38 , 510 , 712 , 914 , 1116 , 1318 , 1520 , 1722 , 1924 , 2126 , 2328 , 2530 , 272 , 294 },
{ 14 , 36 , 58 , 710 , 912 , 1114 , 1316 , 1518 , 1720 , 1922 , 2124 , 2326 , 2528 , 2730 , 292 }
};
return mapping;
}
Then that method can be used in the method to get the pirateID. It can iterate through the array, looking for the value in each sub-array. If it is found, then it will return the index of the sub-array.
private int getPirateID() {
String temp = Integer.toString(disk1.get(0)) + Integer.toString(disk2.get(0));
int pirateID = Integer.parseInt(temp);
int[][] mapping = this.getMapping();
for(int i=0; i<mapping.length; i++) {
for (int j=0; j <mapping[i].length; j++) {
if (mapping[i][j] == pirateID) {
return i;
}
}
}
return -1; // not found
}
This can be demonstrated on ideone.com. When I ran it there, it took 0.04 seconds, even if it has to run through the entire 2-d array. The original code took 0.05 seconds.