我如何通过加入和离开使这些频道动态可见?

How do I make these channels visible dynamically with just joins and leaves?

考虑这个 MVCE:

import os
from time import sleep
from typing import List, Optional


class Member:
    def __init__(self, name: str):
        self.name: str = name


class VoiceChannel:
    def __init__(self, number: int):
        self.number: int = number
        self.members: List[Member] = []
        self.visible = True

    def is_empty(self) -> bool:
        return len(self.members) == 0

    def add_member(self, member: Member):
        self.members.append(member)

    def remove_member(self, member: Member):
        self.members.remove(member)


class System:
    def __init__(self):
        self.channels: List[VoiceChannel] = []
        for channel_number in range(1, 6):
            if channel_number == 1:
                self.channels.append(VoiceChannel(channel_number))
            else:
                _ = VoiceChannel(channel_number)
                _.visible = False
                self.channels.append(_)

    def get_room(self, number: int) -> Optional[VoiceChannel]:
        if number > 0:
            return self.channels[number - 1]

    def on_voice_state_update(
            self,
            member: Member,
            before: Optional[VoiceChannel],
            after: Optional[VoiceChannel]
    ):
        def join():
            pass

        def leave():
            pass

        if after in self.channels:
            join()

        if before in self.channels:
            leave()

    def join(self, member: Member, channel_number):
        self.channels[channel_number - 1].add_member(member)
        self.update_screen()
        self.on_voice_state_update(member, None, self.channels[channel_number])
        self.update_screen()

    def leave(self, member: Member):
        on_leave_channel = None
        for channel in self.channels:
            if member in channel.members:
                on_leave_channel = channel
                channel.remove_member(member)
                self.update_screen()
                break

        if on_leave_channel:
            self.on_voice_state_update(member, on_leave_channel, None)

    def move(self, member: Member, channel_number: int):
        for current_channel in self.channels:
            if member in current_channel.members:
                current_channel.remove_member(member)
                self.update_screen()
                break
        channel = self.get_room(channel_number)
        channel.add_member(member)
        self.update_screen()

    def update_screen(self):
        _ = os.system("cls")
        print("\n> Debate Rooms")
        for channel in self.channels:
            if channel.visible:
                print(f"     Debate {channel.number}")
                if not channel.is_empty():
                    for member in channel.members:
                        print(f"         {member.name}")
                else:
                    print(f" ")

        sleep(1.5)


if __name__ == "__main__":
    system = System()

    # Initialize Members
    john = Member("John")
    jane = Member("Jane")
    abby = Member("Abby")
    jess = Member("Jess")
    hope = Member("Hope")
    kate = Member("Kate")
    liam = Member("Liam")
    noah = Member("Noah")
    jack = Member("Jack")
    luke = Member("Luke")

    # Prime Members
    system.join(john, 1)  # Show Debate 2.
    system.leave(john)  # Hide Debate 2.
    system.join(john, 1)  # Show Debate 2.
    system.join(jane, 1)  # Keep Showing Debate 2.
    system.leave(john)   # Keep Showing Debate 2.
    system.leave(jane)  # Hide Debate 2.
    system.join(john, 1)  # Show Debate 2.
    system.join(jane, 2)  # Show Debate 3.
    system.join(abby, 3)  # Show Debate 4.
    system.leave(john)   # Hide Debate 4 since 1 is available.
    system.move(jane, 1)  # Keep Debate 4 hidden, and Debate 2 shown.

我正尝试根据此要求使这些频道可见和不可见:

  1. 总是只有一个空频道可见。
  2. 用户可以加入或离开可见频道[如果没有用户则频道为空]。
  3. 如果用户加入(单个可见的)空频道,使第一个可用的空频道可见[保持(1)]。
  4. 如果用户离开导致额外的空频道,只显示第一个空频道[再次,保持(1)]

如何仅使用 on_voice_state_update() 中的 join()leave() 函数来实现此功能?我已经尝试了一段时间,但似乎无法弄清楚。

我会创建一个函数来评估您的条件 1,如果不满足则采取相应的行动。此函数可以在当前状态下工作,而不必知道哪个成员 removed/added 到房间:

    def ensure_one_empty_room(self):
        empty_visible_channels = \
            [channel for channel in self.channels if channel.is_empty() and channel.visible]

        if len(empty_visible_channels)==0:
            first_empty_channel = next(channel for channel in self.channels if channel.is_empty())
            if first_empty_channel: 
                first_empty_channel.visible=True

        elif len(empty_visible_channels)>1:
            for channel in empty_visible_channels[1:]:
                channel.visible=False

完整系统 class 将变为:

class System:
    def __init__(self):
        self.channels = [VoiceChannel(i) for i in range(1, 6)]
        self.ensure_one_empty_room()
        self.update_screen()

    def get_room(self, number: int) -> Optional[VoiceChannel]:
        if number > 0:
            return self.channels[number - 1]

    def ensure_one_empty_room(self):
        empty_visible_channels = \
            [channel for channel in self.channels if channel.is_empty() and channel.visible]

        if len(empty_visible_channels)==0:
            first_empty_channel = next(channel for channel in self.channels if channel.is_empty())
            if first_empty_channel: 
                first_empty_channel.visible=True

        elif len(empty_visible_channels)>1:
            for channel in empty_visible_channels[1:]:
                channel.visible=False

    def on_member_change(self):
        self.ensure_one_empty_room()
        self.update_screen()

    def joined_channels(self, member):
        return (channel for channel in self.channels if (member in channel.members))

    def join(self, member: Member, channel_number):
        self.get_room(channel_number).add_member(member)
        self.on_member_change()

    def leave(self, member: Member):
        for channel in self.joined_channels(member):
            channel.remove_member(member)
        self.on_member_change()

    def move(self, member: Member, channel_number: int):
        for channel in self.joined_channels(member):
            channel.remove_member(member)
        self.get_room(channel_number).add_member(member)
        self.on_member_change()

    def update_screen(self):
        os.system("cls")
        print("\n> Debate Rooms")
        for channel in self.channels:
            if channel.visible:
                print(f"     Debate {channel.number}")
                if not channel.is_empty():
                    for member in channel.members:
                        print(f"         {member.name}")
                else:
                    print(f" ")

        sleep(1.5)

注意:

  • 在您的 join() 函数中,没有检查成员是否已经是频道的一部分,因此他可以加入多个频道。因此,我更改为其他功能(移动和离开)以考虑到这一点
  • 我在 Python 中合并了一些很好的 列表理解 功能的示例,仅用于说明目的