/// <summary> /// Enumerate indexes. /// </summary> /// Developer notes: I tried to use a pointer for cards[] too, but it does not changes the speed. static void CombinInternal <ParamT>(int *liveCards, int liveCardsCount, int count, int[] cards, int startPos, EnumerateActionIdxDelegate <ParamT> action, ParamT param) { switch (count) { case 0: action(cards, param); break; case 1: for (int c1 = 0; c1 < liveCardsCount; ++c1) { cards[startPos] = liveCards[c1]; action(cards, param); } break; case 2: for (int c1 = 1; c1 < liveCardsCount; ++c1) { cards[startPos] = liveCards[c1]; for (int c2 = 0; c2 < c1; ++c2) { cards[startPos + 1] = liveCards[c2]; action(cards, param); } } break; case 3: for (int c1 = 2; c1 < liveCardsCount; ++c1) { cards[startPos] = liveCards[c1]; for (int c2 = 1; c2 < c1; ++c2) { cards[startPos + 1] = liveCards[c2]; for (int c3 = 0; c3 < c2; ++c3) { cards[startPos + 2] = liveCards[c3]; action(cards, param); } } } break; case 4: for (int c1 = 3; c1 < liveCardsCount; ++c1) { cards[startPos] = liveCards[c1]; for (int c2 = 2; c2 < c1; ++c2) { cards[startPos + 1] = liveCards[c2]; for (int c3 = 1; c3 < c2; ++c3) { cards[startPos + 2] = liveCards[c3]; for (int c4 = 0; c4 < c3; ++c4) { cards[startPos + 3] = liveCards[c4]; action(cards, param); } } } } break; case 5: for (int c1 = 4; c1 < liveCardsCount; ++c1) { cards[startPos] = liveCards[c1]; for (int c2 = 3; c2 < c1; ++c2) { cards[startPos + 1] = liveCards[c2]; for (int c3 = 2; c3 < c2; ++c3) { cards[startPos + 2] = liveCards[c3]; for (int c4 = 1; c4 < c3; ++c4) { cards[startPos + 3] = liveCards[c4]; for (int c5 = 0; c5 < c4; ++c5) { cards[startPos + 4] = liveCards[c5]; action(cards, param); } } } } } break; default: for (int c1 = count - 1; c1 < liveCardsCount; ++c1) { cards[startPos] = liveCards[c1]; for (int c2 = count - 2; c2 < c1; ++c2) { cards[startPos + 1] = liveCards[c2]; for (int c3 = count - 3; c3 < c2; ++c3) { cards[startPos + 2] = liveCards[c3]; for (int c4 = count - 4; c4 < c3; ++c4) { cards[startPos + 3] = liveCards[c4]; for (int c5 = count - 5; c5 < c4; ++c5) { cards[startPos + 4] = liveCards[c5]; CombinInternal(liveCards, c5, count - 5, cards, startPos + 5, action, param); } } } } } break; } }
/// <summary> /// Combin all possible combinations of cards and calls an action for each combination. /// </summary> /// <param name="cards">Array to put the cards to.</param> /// <param name="startPos">Starting position in the cards array.</param> /// <param name="deadCards">Dead cards. If some shared cards are necessary, put it manually to both cards and deadCards.</param> public static void Combin <ParamT>(DeckDescriptor deckDescr, int count, int[] cards, int startPos, int[] deadCards, int deadCardsCount, EnumerateActionIdxDelegate <ParamT> action, ParamT param) { int[] deckCopy = deckDescr.FullDeckIndexes.ShallowCopy(); for (int i = 0; i < deadCardsCount; ++i) { deckCopy[deadCards[i]] = -1; } int liveCardsLength = deckCopy.Length - deadCardsCount; int *liveCards = stackalloc int[liveCardsLength]; int cnt = 0; for (int i1 = 0; i1 < deckCopy.Length; ++i1) { if (deckCopy[i1] >= 0) { liveCards[cnt++] = deckCopy[i1]; } } Debug.Assert(cnt == liveCardsLength); CombinInternal(liveCards, liveCardsLength, count, cards, startPos, action, param); }