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\$
3
  • \$\begingroup\$ Shouldn't it return a list of card sequences, so a List<List<Card>>? \$\endgroup\$
    – clabe45
    Aug 4, 2018 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, 2018 at 13:38
  • \$\begingroup\$ stackoverflow.com/questions/31615597/… \$\endgroup\$
    – Hardik.N
    Aug 21, 2018 at 10:26

1 Answer 1

-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\$
1
  • \$\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\$ Aug 21, 2018 at 10:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .