/** * Index a hand on every round. This is not more expensive than just indexing the last round. * * @param cards * @param indices an array where the indices for every round will be saved to * @return hands index on the last round */ public long indexAll(int[] cards, long[] indices) { if (rounds > 0) { HandIndexerState state = new HandIndexerState(); for (int i = 0; i < rounds; i++) { indices[i] = indexNextRound(state, cards); } return(indices[rounds - 1]); } return(0); }
/** * Incrementally index the next round. * * @param state * @param cards the cards for the next round only! * @return hand's index on the latest round */ public long indexNextRound(HandIndexerState state, int[] cards) { int round = state.round++; int[] ranks = new int[SUITS]; int[] shiftedRanks = new int[SUITS]; for (int i = 0, j = roundStart[round]; i < cardsPerRound[round]; ++i, ++j) { int rank = cards[j] >> 2, suit = cards[j] & 3, rankBit = 1 << rank; ranks[suit] |= rankBit; shiftedRanks[suit] |= (rankBit >> BitOperations.PopCount((uint)((rankBit - 1) & state.usedRanks[suit]))); } for (int i = 0; i < SUITS; ++i) { int usedSize = BitOperations.PopCount((uint)state.usedRanks[i]), thisSize = BitOperations.PopCount((uint)ranks[i]); state.suitIndex[i] += state.suitMultiplier[i] * rankSetToIndex[shiftedRanks[i]]; state.suitMultiplier[i] *= nCrRanks[RANKS - usedSize, thisSize]; state.usedRanks[i] |= ranks[i]; } for (int i = 0, remaining = cardsPerRound[round]; i < SUITS - 1; ++i) { int thisSize = BitOperations.PopCount((uint)(ranks[i])); state.permutationIndex += state.permutationMultiplier * thisSize; state.permutationMultiplier *= remaining + 1; remaining -= thisSize; } int configuration = permutationToConfiguration[round][state.permutationIndex]; int piIndex = permutationToPi[round][state.permutationIndex]; int equalIndex = configurationToEqual[round][configuration]; long offset = configurationToOffset[round][configuration]; int[] pi = suitPermutations[piIndex]; int[] suitIndex = new int[SUITS], suitMultiplier = new int[SUITS]; for (int i = 0; i < SUITS; ++i) { suitIndex[i] = state.suitIndex[pi[i]]; suitMultiplier[i] = state.suitMultiplier[pi[i]]; } long index = offset, multiplier = 1; for (int i = 0; i < SUITS;) { long part, size; if (i + 1 < SUITS && equal[equalIndex, i + 1]) { if (i + 2 < SUITS && equal[equalIndex, i + 2]) { if (i + 3 < SUITS && equal[equalIndex, i + 3]) { Swap(suitIndex, i, i + 1); Swap(suitIndex, i + 2, i + 3); Swap(suitIndex, i, i + 2); Swap(suitIndex, i + 1, i + 3); Swap(suitIndex, i + 1, i + 2); part = suitIndex[i] + nCrGroups[suitIndex[i + 1] + 1, 2] + nCrGroups[suitIndex[i + 2] + 2, 3] + nCrGroups[suitIndex[i + 3] + 3, 4]; size = nCrGroups[suitMultiplier[i] + 3, 4]; i += 4; } else { Swap(suitIndex, i, i + 1); Swap(suitIndex, i, i + 2); Swap(suitIndex, i + 1, i + 2); part = suitIndex[i] + nCrGroups[suitIndex[i + 1] + 1, 2] + nCrGroups[suitIndex[i + 2] + 2, 3]; size = nCrGroups[suitMultiplier[i] + 2, 3]; i += 3; } } else { Swap(suitIndex, i, i + 1); part = suitIndex[i] + nCrGroups[suitIndex[i + 1] + 1, 2]; size = nCrGroups[suitMultiplier[i] + 1, 2]; i += 2; } } else { part = suitIndex[i]; size = suitMultiplier[i]; i += 1; } index += multiplier * part; multiplier *= size; } return(index); }