Question

Consider a list of items (take a list of voice channels) where each item has these attributes

UML Diagram

System::vc: List of voice channels.

System::on_join(member, before, after): On the event when a member joins a VoiceChannel the first time, it's before is Null and after is a VoiceChannel. When a member switches voice channels, before and after are different VoiceChannels.

System::on_leave(member, before, after): On the event when a member leaves all voice channels (ie: does not switch to another VoiceChannel), before will be a VoiceChannel and after will be Null.

System::get_room(no): Get a VoiceChannel from it's number.

VoiceChannel::number: The number of the VoiceChannel (ie, index of System::vc + 1).

VoiceChannel::is_empty(): Returns True if there are no members in the channel, else False.

VoiceChannel::is_visible(): Returns True if the channel is currently visible, else False.

VoiceChannel::make_visible(): Makes a channel visible to all members. Returns True if successful and False if not.

VoiceChannel::make_invisible(): Makes a channel invisible to all members. Returns True if successful and False if not.


I'm trying to develop an algorithm to obtain this result when applied on System::vc:

  1. When a member joins a VoiceChannel it should make the first invisible and empty channel in the list visible.
  2. If one emptyVoiceChannel is already visible then don't make any new ones visible.
  3. If more than one empty channel is visible then only make the first empty channel visible.

Notes

  1. All VoiceChannel items except the first are invisible in initial state.
  2. A member can only join one VoiceChannel at a time.
  3. A member needs to join at least one VoiceChannel before they can switch between voice channels. So it's not possible to switch from channel 1 to channel 2 without having first already joined channel 1.

What I have tried

Psuedocode

def on_join(member, before, after):
    vc_visible = []
    for vc in self.vc:  # self is an instance of System
        if is_visible(vc):
            vc_visible.append(vc)
    
    last_vc_number = len(vc_visible) + 1
    if last_vc_number == 21:  # Total number of VoiceChannels + 1
        return
    
    self.vc_last = self.get_room(last_vc_number)
    for vc in self.vc:
        if is_visible(vc) and is_empty(vc) and vc.number != 1:
            self.vc_next_visible = vc
            return
        elif vc == self.vc_next_visible:
            await make_visible(self.vc_next_visible)
            return
        else:
            await make_visible(self.vc_last)
            return

async def on_leave(member, before, after):
    vc_visible = []
    for vc in self.vc:  # self is an instance of System
        if is_visible(vc):
            vc_visible.append(vc)

    # Cycle through list from second last to front
    for vc in vc_visible[:len(vc_visible) * -1 :-1]:
        if is_empty(vc) and is_empty(vc_visible[0]):
            await make_invisible(vc)
        elif is_empty(vc):
            if vc != self.vc_next_visible and vc.number != 2:
                await make_invisible(vc)

    for vc in self.vc:
        if is_visible(vc) and is_empty(vc) and vc.number != 1:
            self.vc_next_visible = vc
            return

Question

How do I go about writing psuedo code or a concrete algorithm to make this work with just on_join and on_leave events?

Was it helpful?

Solution

Stop asking things about their state and start telling them what you want. Also, don't use null if you can help it.

With that in mind here's a redesign:

System::on_join(member, after, emptyChannel) On the event when a member joins a VoiceChannel the first time, after is the VoiceChannel they join.

System::on_switch(member, before, after, emptyChannel) When a member switches voice channels, before and after are different VoiceChannels.

System::on_leave(member, before, after, emptyChannel) On the event when a member leaves all voice channels (ie: does not switch to another VoiceChannel), before will be a VoiceChannel and after will be Null.

Both on_switch and on_leave can call leaveChannel(member, before, emptyChannel) and tell the channel about the member leaving. The channel can update it's member list, update it's visibility, or file a tax return, whatever the channel wants to do.

Both on_switch and on_join can call joinChannel(member, after, emptyChannel) and tell the channel about the member leaving. The channel can update it's member list, update it's visibility, or send the member spam email, whatever the channel wants to do.

This might seem weird but you can make the channels smart enough to handle this stuff on their own. All they need to know is that it's time to check if they should be visible, how many members they have, and if empty, if emptyChannel is lower numbered or conversely if it just got filled. With that info they can figure out visibility themselves. You don't have to keep building lists.

Licensed under: CC-BY-SA with attribution
scroll top