[Challenge] Secret Santa 🎁

Secret Santa Code Challenge! :gift:

Secret Santa is a tradition “in which members of a group or community are randomly assigned a person to whom they give a gift. The identity of the gift giver is to remain a secret and should not be revealed.” –Wikipedia

In the spirit of upcoming holidays, we’re doing a Secret Santa code challenge. Details below.

:rocket: Rules to enter:

  • Choose any general-purpose programming language, such as Python, JavaScript, Java, or C++.
  • Originality and readability of your code (make it your own and use style conventions and comments to keep things legible).
  • Submit your code and a picture/GIF of your output by Sunday, December 12th at 11:59 PM EST.

:trophy: Prize

  • One month of Codecademy Pro

Beginner Level:

  • Store the names in an array/list.
  • Pair participants and output the pairs.

Here’s the list of names (or choose your own!)

  • Michel Scott
  • Dwight Schrute
  • Jim Halpert
  • Pam Beesly
  • Jan Levinson
  • Kevin Malone
  • Toby Flenderson
  • Angela Martin
  • Andy Bernard
  • Stanley Hudson
  • Ryan Howard
  • Kelly Kapoor

Intermediate Level:

  • Create a list of names in a text file names.txt.
  • Import the text file in your program.
  • Pair participants using the names and output the pairs.

Optional: Add your flair to this program!

:books: Resources:

:sparkles: Once you’re done…

Share it in a post below. Share a picture/GIF of your finished project and include a link to your Codecademy Workspace link so we can see your code.

10 Likes

I love this challenge - well, I love all things to do with The Office! :slight_smile:

Beginner level written in Python

My code:

5 Likes

This was fun! :santa:

import random

santa_helpers = ['Michael Scott',
                 'Dwight Schrute',
                 'Jim Halpert',
                 'Pam Beesly',
                 'Jan Levinson',
                 'Kevin Malone',
                 'Toby Flenderson',
                 'Angela Martin',
                 'Andy Bernard',
                 'Stanley Hudson',
                 'Ryan Howard',
                 'Kelly Kapoor']


def santas_elves(santa_list):
    """Receives a list of nice people and 
    gives the elves a little help on Christmas
    """
    gift_receivers = santa_list.copy()
       
    print('Santa\'s nice list:')
    print()
    
    # shuffle gift_receivers until all the matches aren't the same person
    while any(santa_list[i] == gift_receivers[i] for i in range(len(santa_list))):
        random.shuffle(gift_receivers)
   
    for f in range(len(santa_list)):
        print(f'{santa_list[f]} gives a gift to --> {gift_receivers[f]}')

        
santas_elves(santa_helpers)

Output:
output

5 Likes

A post was split to a new topic: Off topic, not an entry, learning moment

import random name_list = ['Michel Scott', 'Dwight Schrute', 'Jim Halpert', 'Pam Beesly', 'Jan Levinson', 'Kevin Malone', 'Toby Flenderson', 'Angela Martin', 'Andy Bernard', 'Stanley Hudson', 'Ryan Howard', 'Kelly Kapoor'] #还没有被挑选的人 last_list = name_list.copy() # ############################################# # 按名单顺序从剩余列表中挑选,被挑选出的人从剩余列表中删除 # ############################################# for name in name_list: # 如果自己还没有被选出 if(name in last_list): last_list.remove(name)# 删除自己 pickone = random.choice(last_list) print(name + ' is ' + pickone + '\'s Santa') last_list.append(name)# 将自己放回剩余列表 last_list.remove(pickone)# 删除挑选出的人 # 自己已经被选出 else: pickone = random.choice(last_list) print(name + ' is ' + pickone + '\'s Santa') last_list.remove(pickone)

2 Likes

The seven comments…

  • People who haven’t been selected yet

  • Select from the remaining list in the order of the list, and delete the selected person from the remaining list

  • If I have not been elected

  • Delete yourself

  • Put yourself back in the remaining list

  • Delete the selected person

  • I have been elected

That’s we got from Google. One hopes it follows along yours.

3 Likes

Hi all, was very excited to give this one a try! I wanted to create a solution which tried to stick to functional programming concepts as best as I could. This is something I’ve been practising recently so thought it’d be good to give it a go. The usage of random.shuffle above is good and one I didn’t consider, but I still like my way also.

I have two branches on the Github page, one that’s a single file and one that’s separated the function definitions to make the main script cleaner, feel free to look at either or both. It’s exactly the same code, just with the definitions split up. I’ve also included a replit so it can be run and tested.

Thanks for giving it a look and giving me a chance to further test my skills! See code from the master branch and image of the output below.

from random import choice, randint
from typing import List

# This function loads the names to pair from the local file.
def load_names(name_file: str) -> List[str]:
    with open(name_file, "r") as names:
        return [name.rstrip() for name in names]

# This function selects the second of the pair and then returns that pair as a list
def select_pair(name_list: List[str], not_yet_chosen: List[int], santa: str) -> List[str]:
    return [santa, name_list[choice(not_yet_chosen)]]

# This function recursively cycles through the provided list, and compiles a 2D list of pairings for secret santa
def santas_pairings(name_list: List[str], santa_index: int = 0, chosen: List[int] = [], pairings: List[str] = []) -> List[str]:
    if santa_index == len(name_list):
        return 0
    santa = name_list[santa_index]
    santas_choices = [num for num in range(0, len(name_list)) if num != name_list.index(santa) and num not in chosen]
    # I encountered a rare situation where the last person to pick would only have themselves to choose from. This checks if that has occured and swaps the name with a random person that has already been chosen.
    if len(santas_choices) == 0:
        swapping_index = randint(0, 10)
        swapped = pairings[swapping_index][1]
        pairings[swapping_index][1] = santa
        santas_choices.append(name_list.index(swapped))
    chosen_pairing = select_pair(name_list, santas_choices, santa)
    pairings.append(chosen_pairing)
    chosen.append(name_list.index(chosen_pairing[1]))
    # Recursive function call
    santas_pairings(name_list, santa_index + 1, chosen, pairings)
    return pairings

# This function recursively displays the pairings that have been chosen, with an option for a specific price limit
def display_santas_choices(pairing_list: List[str], index: int = 0, price_limit: int = 20) -> str:    
    if index == len(pairing_list):
        return "complete"
    current_pair = pairing_list[index]
    print(f"{current_pair[0]} will now be Santa for...{current_pair[1]}!")
    # Recursive function call
    display_santas_choices(pairing_list, index + 1)
    if index == 0:
        print(f"\nDon't forget about the ${price_limit} limit!")
    return "complete"

# The main function call
if __name__ == "__main__":
    print("It's that time of year again! Time to select the pairings for this years Secret Santa.\n")
    print("!! Don't let the participants see, otherwise Santa wouldn't be so secret would they?\n")
    name_list = load_names("names.txt")
    santa_pairings = santas_pairings(name_list)
    display_santas_choices(santa_pairings)

image

3 Likes

Here’s my spin on it! Merry Christmas everyone!

Replit Link https://replit.com/@mordyman/secret-santa-codecademy#main.py

image

3 Likes

here’s my entry :slight_smile:

#Store the names in an array/list
#Pair participants and output the pairs

import random

#assuming all elves are participating
santa_elves = ['Michael Scott', 'Dwight Schrute', 'Jim Halpert', 'Pam Beesly', 'Jan Levinson', 'Kevin Malone', 'Toby Flenderson', 'Angela Martin', 'Andy Bernard', 'Stanley Hudson', 'Ryan Howard', 'Kelly Kapoor']

#santa function
def secret_santa(x_lst):  
  random.shuffle(x_lst)
  i = 0
  while i < len(x_lst):
    print(f'{x_lst[i]} will be gifting some holiday flair to {x_lst[i + 1]}. ')
    i += 2
    return x_lst #to see one pairing at a time or call function below to get full list


secret_santa(santa_elves)

3 Likes
#Store the names in an array/list. #Pair participants and output the pairs. import random #all the guys list santa_list = ["John Pretrucci", "John Myung", "Jon Lord", "Rick Wakeman", "Jordan Rudess", "Patatí", "Patatá", "Michel Camilo", "Kazuma", "Steve Vai", "Steve Morse", "Ozzy" ] santa_receivers = santa_list.copy() #pair the people for person in santa_list: if person in santa_receivers: receivers = random.choice(santa_receivers) santa_receivers.remove(receivers) print(f"Wow, {person} is {receivers}'s Secret Santa. Merry Christmas!")

Output:
Captura de tela 2021-12-08 143457

3 Likes

Here is my Java version using minimal library functions. I tried to modularize the code and provide useful comments in the code.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.*;

public class SecretSanta {
    public static void main(String[] args) {
        File inputFile = new File("names.txt");
        List<String> names = readNamesFromFile(inputFile);
        Map<String, String> secretSanta = generateSecretSanta(names);
        printSecretSanta(secretSanta);
    }

    /**
     * Utility method to read from a file
     * @param inputFile
     * @return
     */
    private static List<String> readNamesFromFile(File inputFile) {
        List<String> names = new ArrayList<>();
        try {
            Scanner fileReader = new Scanner(inputFile);
            while (fileReader.hasNext()) {
                //Assuming one line per name
                names.add(fileReader.nextLine());
            }
        } catch (FileNotFoundException fileNotFoundException) {
            System.out.println("Input file not found");
        }
        return names;
    }

    /**
     * Generate a shuffled list from the original list and generate a random secret santa for each name
     * @param names
     * @return
     */
    private static Map<String, String> generateSecretSanta(List<String> names) {
        return zipListsToMap(names, getShuffledList(names));
    }

    /**
     * This method shuffles the given list of strings so that no string is in the original place
     * @param list input list of strings
     * @return shuffled list of strings
     */
    private static List<String> getShuffledList(List<String> list) {
        List<String> shuffled = new ArrayList<>(list);
        for (int i = 0; i < list.size() - 1; i++) {
            int randomIndex = getRandomNumber(i + 1, shuffled.size());
            swapNames(shuffled, i, randomIndex);
        }
        return shuffled;
    }

    /**
     * Combines two lists into a map, assuming that two lists are of same length
     * @param list1 list of keys
     * @param list2 list of corresponding values for keys in list1
     * @return Map
     */
    private static Map<String, String> zipListsToMap(List<String> list1, List<String> list2) {
        Map<String, String> map = new HashMap<>();
        for(int i = 0; i < list1.size(); i++) {
            map.put(list1.get(i), list2.get(i));
        }
        return map;
    }

    /**
     * Utility method to print a map
     * @param secretSanta a Map
     */
    private static void printSecretSanta(Map<String, String> secretSanta) {
        for (String name : secretSanta.keySet()) {
            System.out.println(name + " -> " + secretSanta.get(name));
        }
    }

    /**
     * Generate a random number between [min, max) - min inclusive, max exclusive
     * @param min : int
     * @param max : int
     * @return a random integer in the given range
     */
    public static int getRandomNumber(int min, int max) {
        return (int) ((Math.random() * (max - min)) + min);
    }

    /**
     * Swap two elements in a list at index1, and index2
     * @param names : List of strings
     * @param index1 : first  index
     * @param index2 : second index
     */
    private static void swapNames(List<String> names, int index1, int index2) {
        String temp = names.get(index1);
        names.set(index1, names.get(index2));
        names.set(index2, temp);
    }
}
3 Likes

Not my best code ever but here you go:

Screenshot 2021-12-08 13.48.47

Got a little carried away with the output, so you really gotta run it for the full experience.
Here’s the code: SecretSanta

Thanks for the challenge!

7 Likes

Nicely done! Though you don’t seem to have any catch preventing people from being their own Santa. Could be something to look into.

1 Like

Looks like poor Jan is her own Secret Santa.
:eyes:

You also have an original list of 12 names, but only 8 secret Santas. I ran your code a few times, and had as many as 3 of the 8 get paired with themselves. :man_shrugging:

Fairly minimalist approach. Thanks for the fun distraction, @lilybird :wink:

Code

3 Likes

Just a for fun entry in c++17.

#include <string>
#include <vector>
#include <random>
#include <iostream>
#include <fstream>

struct Participant {
    std::string name;
    std::string giveTo;
    std::string getFrom;
};

std::vector<std::string> getNamesFromFile(){
    std::vector<std::string> names;
    std::ifstream file ("names.txt");
    if(std::string name; file.is_open()) {
        while(std::getline(file, name)){
            names.push_back(name);
        }
    }
    return names;
}

void shuffleNames(std::vector<std::string>& vec) {
    std::random_device rd{};
    std::default_random_engine rng{rd()};
    std::shuffle(vec.begin(), vec.end(), rng);
}

void printSecretSantas(const std::vector<Participant> &participants) {
    for(auto&& p : participants) {
        std::cout << p.name << " Gives a gift to " << p.giveTo << " and receives a gift from " << p.getFrom << "\n";
    }
}

int main() {
    auto names = getNamesFromFile();
    shuffleNames(names);
    std::vector<Participant> participants;
    auto firstParticipant = *names.begin();
    auto lastParticipant = *(names.end()-1);
    // First in line gives to next in line, receives from last in line
    participants.emplace_back(Participant{firstParticipant, *(names.begin()+1), lastParticipant});
    // Last in line gives to first in line, receives from second to last in line
    participants.emplace_back(Participant{lastParticipant, firstParticipant, *(names.end()-2)});
    // Give to the next in line, receive from previous in line
    for(std::size_t i = 1; i < names.size()-1; ++i) {
        participants.emplace_back(Participant{names[i], names[i+1], names[i-1]});
    }
    printSecretSantas(participants);
}
2 Likes

Very fancy! Nice work.

2 Likes

Thank you! Pairing them up seemed too easy and it did say to add some flair :smiley:
I love your added message for Packer :joy: I thought about doing something like that for Kinsey in mine.

2 Likes

Not an entry, just don’t get to play with files very much…

https://replit.com/@mtf/Secret-Santa

2 Likes

This one is slightly more original and might make a decent entry…

https://replit.com/@mtf/Key-Ring-Pairs

I stole the idea from @midlindner of what looked like a key-ring so went to work from that perspective.

3 Likes