Home > Blockchain >  Randomizing lists with set rules
Randomizing lists with set rules

Time:11-28

I have a project where I want to make a list randomizer with a set of rules.

Let's say I have 1 list named guests with 9 items, 1 named hosts with 4 items, and one named meals with 3 items.

Now I want to randomize these guests across the hosts so every host get 3 guests, witch is fair enough. Now they will all be connected to the first item in meal. Problem arrives when I want to scramble them again across different hosts for meal 2, but so that none of the guests that have been together meet again for the next 2 meals.

I do in the end want to have it so I can have a dynamic list of hosts and guests that will solve itself after they've been typed in.

I don't want the code solved, just looking for the means to get there.

CodePudding user response:

There are two things you will need to keep track of: a) Which hosts have already hosted which guests b) For each meal, which guests have already been assigned out.

Item a can be done with a dictionary that uses the name of each host as a key. Item b just needs to be a list that gets reset for each new meal.

Once you've started keeping track of that information, then right before choosing the guests that will be assigned to a host, you can use this information that you are keeping track of to create a second intermediary list that only includes guests that can be chosen and randomly choose one of them.

Below is my solution to this problem:

import random

class Meal_Schedule:
    ''' A class for repeatedly dividing up multiple hosts amongst multiple guests
    such that a guest will never be hosted by the same host twice
    and will always be placed with different guests '''

    def __init__(self, guests: list, hosts: list, meals: list):
        ''' guests and hosts should both be lists. Duplicate guest or host names are not supported,
        and the duplicate names will be ignored. '''
        self.guests = guests
        self.hosts = hosts
        self.meals = meals
        self.previously_assigned = {host:[] for host in hosts}

    def create_meal_schedule(self):
        ''' Do all of the scheduling
        Example of the dictionary returned:
        {
        'Hamburger': {'host 1': ['Guest D', 'Guest A'],
                      'host 2': ['Guest B', 'Guest C']},
        'Pizza': {'host 1': ['Guest B', 'Guest C'],
                  'host 2': ['Guest A', 'Guest D']}
        }
        '''
        ret = {}
        for meal in self.meals:
            ret[meal] = self.plan_next_meal()
        return ret

    def plan_next_meal(self, guests_per_host=None):
        ''' Plans the next meal
        guests_per_host should be a positive integer, or None to automatically calculate a sensible value
        Returns a dictionary containing each host's guest list for the next meal '''

        # self.previously_assigned keeps track of who has been assigned to a host in the past
        # so we don't assign a guest to the same host twice
        # and assigned_this_round will keep track of which guests have already been given a seat this round
        # so we don't double book a guest to two different hosts

        if guests_per_host is None:
            if not self.hosts:
                # So we don't get a vague division by zero error, we raise this error instead
                raise RuntimeException('Must have at least one host')
            guests_per_host = len(self.guests) // len(self.hosts)
            if guests_per_host < 1:
                guests_per_host = 1

        assert guests_per_host > 1, 'guests_per_host must be an integer greater than 1'

        ret = {}
        assigned_this_round = []
        for host in self.hosts:
            guest_list = self._create_guest_list( host, guests_per_host,
                                                  exclude_these_guests = [*self.previously_assigned[host], *assigned_this_round] )

            assigned_this_round.extend(guest_list)
            ret[host] = guest_list
            self.previously_assigned[host].extend(guest_list)

        return ret

    def _create_guest_list(self, host, guests_per_host, exclude_these_guests):
        ''' used when planning a meal to create a host's guest list '''
        guests_pool = [ guest for guest in self.guests if guest not in exclude_these_guests ]

        if len(guests_pool) <= guests_per_host:
            return guests_pool

        return random.sample(guests_pool, guests_per_host)

    def display_schedule(self, schedule=None):
        ''' displays a schedule created with create_meal_schedule
        on the console in a nice way '''
        if schedule is None:
            schedule = self.create_meal_schedule()

        print()
        for meal, plan in schedule.items():
            print(f'-- {meal} Meal Plan --'.upper())
            print()
            for host, guest_list in plan.items():
                print(f'Host: {host}')
                print('Guess list:')
                for guest in guest_list:
                    print(f' {guest}')
                print()
            print()
            print()

guests = [f'Guest {x}' for x in 'ABCDEFGHI']
hosts = ['host1', 'host2', 'host3', 'host4']
meals = ['Hamburger', 'Pizza', 'Eggs']

scheduler = Meal_Schedule(guests, hosts, meals)
scheduler.display_schedule()
  • Related