/// <summary> /// Same as Combin, contains additional user-defined parameter that will be passed to the delegate. /// </summary> // Code is copied from non-generic Combin. Code reuse decreases performace by 10%. public static void Combin <ParamT>(DeckDescriptor deckDescr, int count, CardSet sharedCards, CardSet deadCards, EnumerateActionDelegate <ParamT> action, ParamT param) { UInt64 deadMask = deadCards.bits | sharedCards.bits; UInt64 *pLiveCardMasks = stackalloc UInt64[deckDescr.Size]; int liveCardsCount = 0; for (int c = 0; c < deckDescr.Size; ++c) { UInt64 bits = deckDescr.CardSets[c].bits; if ((bits & deadMask) == 0) { pLiveCardMasks[liveCardsCount++] = bits; } } CombinInternal(sharedCards.bits, pLiveCardMasks, liveCardsCount, count, action, param); }
private static void CombinInternal <ParamT>(ulong m0, ulong *pLiveCardMasks, int liveCardsCount, int count, EnumerateActionDelegate <ParamT> action, ParamT param) { ulong m1; ulong m2; ulong m3; ulong m4; CardSet result; // Alogritm for liveCardsCount = 10, count = 3: // Live Masks: 0 1 2 3 4 5 6 7 8 9 // 1st loop b -> e // 2nd loop b -> e // 3rd loop b -> e switch (count) { case 0: result.bits = m0; action(ref result, param); break; case 1: for (int c1 = 0; c1 < liveCardsCount; ++c1) { result.bits = m0 | pLiveCardMasks[c1]; action(ref result, param); } break; case 2: for (int c1 = 1; c1 < liveCardsCount; ++c1) { m1 = m0 | pLiveCardMasks[c1]; for (int c2 = 0; c2 < c1; ++c2) { result.bits = m1 | pLiveCardMasks[c2]; action(ref result, param); } } break; case 3: for (int c1 = 2; c1 < liveCardsCount; ++c1) { m1 = m0 | pLiveCardMasks[c1]; for (int c2 = 1; c2 < c1; ++c2) { m2 = m1 | pLiveCardMasks[c2]; for (int c3 = 0; c3 < c2; ++c3) { result.bits = m2 | pLiveCardMasks[c3]; action(ref result, param); } } } break; case 4: for (int c1 = 3; c1 < liveCardsCount; ++c1) { m1 = m0 | pLiveCardMasks[c1]; for (int c2 = 2; c2 < c1; ++c2) { m2 = m1 | pLiveCardMasks[c2]; for (int c3 = 1; c3 < c2; ++c3) { m3 = m2 | pLiveCardMasks[c3]; for (int c4 = 0; c4 < c3; ++c4) { result.bits = m3 | pLiveCardMasks[c4]; action(ref result, param); } } } } break; case 5: for (int c1 = 4; c1 < liveCardsCount; ++c1) { m1 = m0 | pLiveCardMasks[c1]; for (int c2 = 3; c2 < c1; ++c2) { m2 = m1 | pLiveCardMasks[c2]; for (int c3 = 2; c3 < c2; ++c3) { m3 = m2 | pLiveCardMasks[c3]; for (int c4 = 1; c4 < c3; ++c4) { m4 = m3 | pLiveCardMasks[c4]; for (int c5 = 0; c5 < c4; ++c5) { result.bits = m4 | pLiveCardMasks[c5]; action(ref result, param); } } } } } break; default: for (int c1 = count - 1; c1 < liveCardsCount; ++c1) { m1 = m0 | pLiveCardMasks[c1]; for (int c2 = count - 2; c2 < c1; ++c2) { m2 = m1 | pLiveCardMasks[c2]; for (int c3 = count - 3; c3 < c2; ++c3) { m3 = m2 | pLiveCardMasks[c3]; for (int c4 = count - 4; c4 < c3; ++c4) { m4 = m3 | pLiveCardMasks[c4]; for (int c5 = count - 5; c5 < c4; ++c5) { CombinInternal(m4 | pLiveCardMasks[c5], pLiveCardMasks, c5, count - 5, action, param); } } } } } break; } }