简体   繁体   中英

How to put lists into one larger list in a certain order for certain conditions? - Python 3.x

Right now, I have a code that look something along the lines of:

def get_newdeck(choice, P1, P2, P3):
    deck = []
    if choice == 1:
        deck = P2+P1+P3
        return deck
    elif choice == 2:
        deck = P1+P2+P3
        return deck
    else:
        deck = P1+P3+P2
        return deck

This is part of a code that is part of a code for a magic trick, which guesses the user's card from a 'deck' of 21. choice is a user input (integer that is either 1, 2, or 3) for which pile the card was previously in, P1, P2, P3 are lists that represent the three piles; more is explained about these piles below.
An algorithmic card trick works as follows:

  1. The magician deals 21 shuffled playing cards face up into three piles working left-to-right row-by-row. The first time the magician does this an audience member is asked to choose one of the cards and keep their choice secret.

  2. The magician asks the audience member to say whether their card is in the first, second or third pile.

3. The magician collects the cards pile by pile ensuring the selected pile is placed in between the other two piles.

  1. Steps 1-3 are repeated 2 more times.

  2. Once these steps are completed, the chosen card will 'magically' be in the middle of the deck of 21 cards.

The step in question is step three, and I am trying to make it look less repetitive.

Is there a way that I could get my code (shown above) to work using a loop? FYI I am using Python-3.x

If you want it, here is the full code - I know it's messy, and there are no comments, but I am trying to fix it, starting with the 'messy' part.

import random

def get_cards():
    nums, suits=['Ace','2','3','4','5','6','7','8','9','10','Jack','Queen','King'], ['Hearts','Clubs','Diamonds','Spades']
    cards_dealt=[]
    while len(cards_dealt) < 22:
        card = random.choice(nums) + " of " + random.choice(suits)
        if card not in cards_dealt:
            cards_dealt.append(card)
        else:
            continue        
    return cards_dealt


def get_piles(deck):
    P1, P2, P3 = [], [], []
    for i in range(21):
        if i%3 == 0:
            P1.append(deck[i])
        elif i%3 == 1:
            P2.append(deck[i])
        else:
            P3.append(deck[i])
    return P1, P2, P3

#####################################
def get_newdeck(choice, P1, P2, P3):
    deck = []
    if choice == 1:
        deck = P2+P1+P3
        return deck
    elif choice == 2:
        deck = P1+P2+P3
        return deck
    else:
        deck = P1+P3+P2
        return deck
#####################################

def main():
    deck = get_cards()
    print("Choose a card and remember it")
    for x in range(3):
        P1, P2, P3 = get_piles(deck)
        piles = {'Pile 1':P1, 'Pile 2': P2, 'Pile 3':P3} 
        for numpile, pile in sorted(piles.items()):
            print()
            print(numpile,': ')
            for card in pile:
                print(card)
        print()
        choice = 0
        while choice > 3 or choice < 1:
            while True:
                try:
                    choice = int(input("Which pile is your card in? (1-3)? > "))
                    break
                except ValueError:
                    print("Must be a number")
        deck = get_newdeck(choice, P1, P2, P3)
    print()
    print('Your card is {}'.format(deck[10]))


main()

You could do something like this:

def get_newdeck(choice, P1, P2, P3):
    chunks = [P1, P2, P3]
    idx = choice-1
    deck = chunks[(idx-1) % 3]+chunks[idx % 3]+chunks[(idx+1) % 3]
return deck

I'm taking idx=choice-1 so their choice is 0, 1, or 2 which would match up well with the three chunks of cards in the chunks list. Since chunks[idx] is their selected pile now, and chunks[idx-1] and chunks[idx+1] are the piles before and after their selected pile respectively, you create deck by putting their pile between the other two. The % (modulo operation) just makes sure that if we go outside of the 0,1,2 range we wrap the result back into that range.

This is easy to visualize if you image their choice had been 2. Then the piles are just in P1, P2, P3 order.

If the user selects the first pile, idx would be 0, and the pile before that would be -1. Modulo 3 this becomes 2, which is the last pile in the sequence.

First of all, I don't think your code looks that repetitive for 3 cases. But for the sake of exchanging idea, here's what I think:

since you want choice position to be swapped with middle element, in this case index 1 (a list with three elements, the indexes would be 0, 1, 2 ), you can do

piles[choice - 1], piles[1] = piles[1], piles[choice - 1]

(of course if choice = 2 , nothing changes)

The test code:

def get_newdeck(choice, P1, P2, P3):
    piles = [P1, P2, P3]
    piles[choice - 1], piles[1] = piles[1], piles[choice - 1]
    deck = []
    for pile in piles:
        deck.extend(pile)
    return deck


if __name__ == "__main__":
    choice = 1
    P1 = [1, 2]
    P2 = [3, 4]
    P3 = [5, 6]
    deck = get_newdeck(choice, P1, P2, P3)
    print(deck)

I don't think there is any serious problem with your code. For a list with 3 elements it is much readable if you do what you are already doing rather then writing unnecessary messy loops.

I was playing a bit with your code and I changed just a few things, mainly the looks :)

import random

def get_cards():
    nums, suits=['A','2','3','4','5','6','7','8','9','10','J','Q','K'], [u'\u2665',u'\u2663',u'\u2666',u'\u2660']
    cards_dealt=[]
    while len(cards_dealt) < 22:
        card = random.choice(nums) + random.choice(suits)
        if card not in cards_dealt:
            cards_dealt.append(card)
        else:
            continue        
    return cards_dealt


def get_piles(deck):
    P1 = [deck[i] for i in range(0,21,3)]
    P2 = [deck[i] for i in range(1,21,3)]
    P3 = [deck[i] for i in range(2,21,3)]
    return P1, P2, P3

#####################################
def get_newdeck(choice, P1, P2, P3):
    deck = P1+P3+P2
    if choice == 1:
        deck = P2+P1+P3
    elif choice == 2:
        deck = P1+P2+P3
    return deck
#####################################

def main():
    deck = get_cards()
    print("Choose a card and remember it")
    for x in range(3):
        P1, P2, P3 = get_piles(deck)
        piles = {'Pile 1':P1, 'Pile 2': P2, 'Pile 3':P3} 
        for numpile, pile in sorted(piles.items()):
            print(numpile+': ', end='\t')
            for card in pile:
                print(card, end='\t')
            print()
        print()
        choice = 0
        while choice > 3 or choice < 1:
            while True:
                try:
                    choice = int(input("Which pile is your card in? (1-3)? > "))
                    break
                except ValueError:
                    print("Must be a number")
        deck = get_newdeck(choice, P1, P2, P3)
    print()
    print('Your card is {}'.format(deck[10]))

main()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM