1
\$\begingroup\$

I have a hand of 13 cards (chosen from 2 standard decks of 52 cards + 4 jokers, so it's possible for the same card to appear multiple times).

I want to search this deck to find sequences according to the rules of Indian Rummy:

  • A sequence must contain at least 3 cards, or up to 10 cards

    (We need at least two sequences to win / minimize loss penalties, so at least 3 cards in the hand of 13 need to be left over to form another sequence)

  • Cards in a sequence have consecutive rank:

    2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A (wild cards count as any rank)

  • A sequence must be all of the same suit:

    ♦, ♣, ♠, ♥ (wild cards can count as any suit)

  • A sequence is called "pure" if it contains no wild cards standing in for other cards.

    eg. if Jacks are wild, the sequence 10♥, J♥, Q♥ is a pure sequence, while the (also valid) sequence 3♣, 4♣, 5♣, J♥, 7♣ is not a pure sequence.

Here's what I've come up with so far, but it does not correctly find all sequences matching the rules above.

private List<Card> FindSequences()
{
    List<Card> sequence = new List<Card>();

    int Count = 0;

    //sort in order
    cards = cards.OrderBy (i => i.FaceValue).ToList ();
    sequence.Add(cards[Count]);

    //------------------------------------------------------------------------------------------------------//

    for(int i = 1; i < 9; i++)
    {
        if((cards[i - 1].cardRank == cards[i].cardRank - 1) && (cards[i].cardRank == cards[i + 1].cardRank - 1) && (cards[i + 1].cardRank == cards[i + 2].cardRank - 1) )//&& (cards[i + 2].cardRank == cards[i + 3].cardRank - 1))
        {
            sequence.Add (cards [i - 1]);
            sequence.Add (cards [i]);
            sequence.Add (cards [i + 1]);
        }
        else 
        {
            Count++;
            //check If Sequence Less Then 3 Clear Data
            if(sequence.Count < 3)
                sequence.Clear ();
        }
    }

    wildCard.Clear ();
    return sequence;
}
\$\endgroup\$
  • \$\begingroup\$ Shouldn't it return a list of card sequences, so a List<List<Card>>? \$\endgroup\$ – clabe45 Aug 4 '18 at 4:00
  • \$\begingroup\$ Cards in a sequence have consecutive rank: 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A(Low or HighCard) (wildcards count as any rank) \$\endgroup\$ – Hardik.N Aug 13 '18 at 13:38
  • \$\begingroup\$ stackoverflow.com/questions/31615597/… \$\endgroup\$ – Hardik.N Aug 21 '18 at 10:26
-1
\$\begingroup\$

var suites = { 'clubs' : [], 'diamonds' : [], 'hearts' : [], 'spades' : [], 'stars' : [] }; var wilds = []; var buckets = { 3 : [], 4 : [], 5 : [], 6 : [], 7 : [], 8 : [], 9 : [], 10 : [], 11 : [], 12 : [], 13 : [] }; //can have more then one run/set so these are used to hold valid runs/sets var runs = []; var sets = []; var r_num = -1; //starts at -1 so ++ will give 0 index var s_num = -1;

CLUBS, DIAMONDS, HEARTS, SPADES, STARS = range(5) WILD = 0

testHand = [(CLUBS,3), WILD, (SPADES,3), (CLUBS,4), (CLUBS,5), (CLUBS,6), (CLUBS,6), (CLUBS,7), (CLUBS,8), (SPADES,10), (HEARTS,10), WILD]

def nextInRun(card):
if card[1] == 13:
    raise ValueError("cannot determine next card in run for %s" % str(card))
    return (card[0],card[1]+1)

        def prevInRun(card):
        if card[1] == 3:
            raise ValueError("cannot determine previous card in run for %s" % str(card))
            return (card[0],card[1]-1)

                def fit2Set(card1, card2):
                return card1 == WILD or card2 == WILD or card1[1] == card2[1]

                    START_RUN, START_SET = range(2)

def removeCard(hand, card, startIdx=None):
hand = copy.deepcopy(hand)
if startIdx != None and hand.index(card) < startIdx:
    startIdx -= 1
    hand.remove(card)
    return ((hand, startIdx) if startIdx != None else hand)

        def startMoves(handr1,card1,startIdx):
        if card1 == WILD:
            #print "trying to start run with 1 WILD card"
            for card2 in set(handr1):
                handr2,startIdx = removeCard(handr1, card2, startIdx)
if card2 == WILD:
    #print "trying to start run with 2 WILD cards"
    for card3 in set(handr2):
        handr3,startIdx = removeCard(handr2, card3, startIdx)
if card3 == WILD:
    yield (START_RUN, 3*[WILD], handr3, startIdx)
else:
    try:
    card2v = prevInRun(card3)
    card1v = prevInRun(card2v)
    yield (START_RUN, [card1,card2,card3], handr3, startIdx)
    except ValueError:
    pass
    else:
        #print "trying to start run with WILD card and %s" % str(card2)
        try:
        card1v = prevInRun(card2)
        card3 = nextInRun(card2)
        #print "card3 = %s, handr2 = %s" % (str(card3),str(handr2))
        canContinueRun = card3 in handr2
        if not canContinueRun and WILD in handr2:
            card3 = WILD
            canContinueRun = True
        if canContinueRun:
            handr3,startIdx = removeCard(handr2, card3, startIdx)
yield (START_RUN, [card1,card2,card3], handr3, startIdx)
except ValueError:
pass
return # no need to start a set with a WILD
    else:
        try:
        card2v = card2 = nextInRun(card1)
        canContinueRun = card2 in handr1
        #print "card2 = %s, handr1 = %s" % (str(card2),str(handr1))
        if not canContinueRun and WILD in handr1:
            card2v = card2
            card2 = WILD
            canContinueRun = True
        if canContinueRun:
            handr2,startIdx = removeCard(handr1, card2, startIdx)
card3 = nextInRun(card2v)
canContinueRun = card3 in handr2
#print "card3 = %s, handr2 = %s" % (str(card3),str(handr2))
if not canContinueRun and WILD in handr2:
    card3 = WILD
    canContinueRun = True
if canContinueRun:
    handr3,startIdx = removeCard(handr2, card3, startIdx)
yield (START_RUN, [card1,card2,card3], handr3, startIdx)
except ValueError:
pass
handrs = copy.deepcopy(handr1)
for card2 in set(handr1):
    handrs.remove(card2)
    if not fit2Set(card1,card2):
        continue
        handr2,startIdx = removeCard(handr1, card2, startIdx)
for card3 in set(handrs):
    if not fit2Set(card1,card3):
        continue
        handr3,startIdx = removeCard(handr2, card3, startIdx)
yield (START_SET, [card1,card2,card3], handr3, startIdx)

def startings(hand,startIdx=0,runs=[],sets=[]):
#print "get startings for\n hand = %s\n startIdx = %d\n runs = %s\n sets = %s" % (str(hand),startIdx,str(runs),str(sets))
if len(hand) == 0 or startIdx >= len(hand):
    yield copy.deepcopy(hand),copy.deepcopy(runs),copy.deepcopy(sets)
return
    card = hand[startIdx]
        while hand.index(card) < startIdx:
            startIdx += 1 # do not try to start with the same card twice here
                if startIdx >= len(hand):
                    yield copy.deepcopy(hand),copy.deepcopy(runs),copy.deepcopy(sets)
        return
            card = hand[startIdx]
                #print " actual startIdx = %d" % startIdx
                handr = removeCard(hand, card)
                for move in startMoves(handr, card, startIdx):
                    if move[0] == START_RUN:
                        runs2 = copy.deepcopy(runs)
                        runs2.append(move[1])
                        for starting in startings(move[2], move[3], runs2, sets):
                            yield starting
                            elif move[0] == START_SET:
                            sets2 = copy.deepcopy(sets)
                            sets2.append(move[1])
                            for starting in startings(move[2], move[3], runs, sets2):
                                yield starting
                                for h,r,s in startings(hand, startIdx+1, runs, sets):
                yield h,r,s

                def runExtensions(run,handSet):
                if set(run) == set([WILD]): # run consists only of WILD cards
                    for card in handSet:
                        yield card
                else:
                    runUnique = list(set(run))
                        cardv = runUnique[0] if runUnique[0] != WILD else runUnique[1]
                            idx = run.index(cardv)
                            lastCardVal = cardv
                            while idx < len(run)-1:
                                lastCardVal = nextInRun(lastCardVal)
                                idx += 1
                                try:
                                nextCardVal = nextInRun(lastCardVal)
                                if nextCardVal in handSet:
                                    yield nextCardVal
                                    return
                                        if WILD in handSet:
                                            yield WILD
                                            except ValueError:
                                            pass

                                            def fillings(hand, runs, sets):
                                        if len(runs) > 0:
                                            run1 = runs[0]
                                            noExtensionFound = True
                                            usedWildExtension = False
                                            for runExtension in runExtensions(run1,set(hand)):
                                                noExtensionFound = False
                                                run1e = copy.deepcopy(run1)
                                                run1e.append(runExtension)
                                                handr = removeCard(hand, runExtension)
                                                runse = [run1e] + copy.deepcopy(runs[1:])
                                                for filling in fillings(handr, runse, sets):
                                                    yield filling
                                                    if runExtension == WILD:
                                                        usedWildExtension = True
                                                        # when extending with WILD: also try without extending the first run; WILD card could be needed in another run
                                                    if noExtensionFound or usedWildExtension and len(runs) > 1:
                                                        for h,r,s in fillings(hand, copy.deepcopy(runs[1:]), sets):
                        r = [run1] + r
                        yield h,r,s
                return
                    handr = copy.deepcopy(hand)
                        setse = copy.deepcopy(sets)
                        for card in hand:
                            for set_i in setse:
                                if fit2Set(card, set_i[0]):
                                    handr.remove(card)
                                    set_i.append(card)
                                    break
                                    yield handr,[],setse

                        def valueCard(card):
                        if card == WILD:
                            return 20
                                return card[1]

                                    def value(hand):
                                    return sum([valueCard(card) for card in hand])

                                        def strRepSuit(suit):
                                        if suit == CLUBS:
                                            return 'clubs'
                                                if suit == DIAMONDS:
                                                    return 'diamonds'
                                                        if suit == HEARTS:
                                                            return 'hearts'
                                                                if suit == SPADES:
                                                                    return 'spades'
                                                                        if suit == STARS:
                                                                            return 'stars'

                                                                                def strRepCard(card):
                                                                                if card == WILD:
                                                                                    return 'WILD'
                                                                                        return '%s%d' % (strRepSuit(card[0]), card[1])

                                                                                            def strRepCardSuit(card):
                                                                                            if card == WILD:
                                                                                                return 'WILD'
                                                                                                    return strRepSuit(card[0])

                                                                                                        def strRepVal(card):
                                                                                                        if card == WILD:
                                                                                                            return 'WILD'
                                                                                                                return '%d' % card[1]

                                                                                                                    def strRepRun(run):
                                                                                                                    setRun = set(run)
                                                                                                                        if setRun == set([WILD]):
                                                                                                                            return '%d * %s' % (len(run),strRepCard(run[0]))
                                                                                                                                runUnique = list(setRun)
                                                                                                                                suit = (runUnique[0] if runUnique[0] != WILD else runUnique[1])[0]
                                                                                                                                return '%s %s' % (strRepSuit(suit), ','.join([strRepVal(card) for card in run]))

                                                                                                                                    def strRepSet(set_):
                                                                                                                                    setUnique = list(set(set_))
                                                                                                                                    val = (setUnique[0] if setUnique[0] != WILD else setUnique[1])[1]
                                                                                                                                    return '%d %s' % (val, ','.join([strRepCardSuit(card) for card in set_]))

                                                                                                                                        def strRepSol(hand,runs,sets):
                                                                                                                                        return ' runs: %s\n sets: %s\n hand: %s\n hand value: %d' % ('; '.join([strRepRun(run) for run in runs]), '; '.join([strRepSet(set_) for set_ in sets]), ','.join([strRepCard(card) for card in hand]), value(hand))

                                                                                                                                            def optimizeHand(hand):
                                                                                                                                            lowestHandValue = value(hand)
                                                                                                                                            bestSolution = hand,[],[]
                                                                                                                        for handr,runs,sets in startings(hand):
                                                                                                                            #print "starting with\n runs = %s\n sets = %s\n handr = %s" % (str(runs),str(sets),str(handr))
                                                                                                                            if len(runs) == 0 and len(sets) == 0:
                                                                                                                                continue
                                                                                                                            if len(handr) == 0:
                                                                                                                                print "solution generated without filling"
                                                                                                                                lowestHandValue = 0
                                                                                                                                    bestSolution = [],runs,sets
                                                                                                                        break
                                                                                                                        for solution in fillings(handr,runs,sets):
                                                                                                                            handValue = value(solution[0])
                                                                                                                                if handValue < lowestHandValue:
                                                                                                                                    lowestHandValue = handValue
                                                                                                                                    bestSolution = solution
                                                                                                                                    print "solution improved:\n%s" % strRepSol(bestSolution[0], bestSolution[1], bestSolution[2])
                                                                                                                                if lowestHandValue == 0:
                                                                                                                                    break
                                                                                                                                if lowestHandValue == 0:
                                                                                                                                    break
                                                                                                                                    print "best solution:\n%s" % strRepSol(bestSolution[0], bestSolution[1], bestSolution[2])
                                                                                                                                    #return lowestHandValue, bestSolution
\$\endgroup\$
  • \$\begingroup\$ If you answer your own question, it would be really helpful if you could describe how you solved it instead of just pasting code, so people having a similar problem can benefit from it. \$\endgroup\$ – TomTsagk Aug 21 '18 at 10:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.