#!/usr/bin/env python3 from coldcall import ColdCall import re import discord import config import random ## create the coldcall object cc = ColdCall() class ColdCallBot (discord.Client): async def on_ready(self): print(f'Logged on as {self.user}! Ready for class!') async def on_message(self, message, voice_channel = 'Class Sessions'): if message.author == self.user: return if message.content.startswith('$next'): if message.channel.category: if cc.course != message.channel.category: cc.update_course(message.channel.category) classroom = [x for x in message.guild.voice_channels if x.name == voice_channel and x.category_id == message.channel.category_id][0] present_students = [] for member in classroom.members: if 'Students' in [r.name for r in member.roles]: present_students.append(re.sub(r'^(.*)\#.*$', r'\1', member.name)) # print who is online print(f'currently online: {",".join(present_students)}') if len(present_students) < 1: msg_text = "I don't see any students currently in the Classroom Voice channel!" else: msg_text = cc.coldcall(present_students) await message.channel.send(msg_text) # TODO: Only let admin send this command if (message.content.startswith('$network game')) and ('Teachers' in [r.name for r in message.author.roles]): print("Starting the game") if message.channel.category: if cc.course != message.channel.category: cc.update_course(message.channel.category) classroom = [x for x in message.guild.voice_channels if x.name == voice_channel and x.category_id == message.channel.category_id][0] present_students = [] for member in classroom.members: if 'Students' in [r.name for r in member.roles]: present_students.append(member) self.assignments = get_assignments(present_students, edgelist = './network_game/test_edgelist.csv') # Build a mapping from names to user objects so that people can refer to users self.active_list = {x.name: x for x in self.assignments} self.observers = [x for x in classroom.members if x not in self.assignments] if self.assignments is not None: for student in self.assignments: await student.send(f"You are allowed to talk to:") for neighbor in self.assignments[student]['neighbors']: await student.send(f"{neighbor.mention}") await student.send(f"You have these resources: {self.assignments[student]['has']}.") await student.send(f"You need: {self.assignments[student]['needs']}.") else: for student in present_students: await student.send("Not enough students to play") if message.content.startswith('$send'): try: _, resource, u_to = message.content.split(' ') except: await message.author.send("Badly formed command. It has to be '$send resource @user'") if u_to not in self.active_list: await message.author.send(f"I can't find {u_to} in the list of users. Make sure the command is formatted as $send resource @user") else: u_to = self.active_list[u_to] gave_resource = self.give_resource(resource, message.author, u_to) if gave_resource == True: finished = self.is_finished(u_to) await message.author.send(f"{resource} sent to {u_to}") await message.author.send(f"You now have {self.assignments[message.author]['has']} and you need {self.assignments[message.author]['needs']}") if finished: await u_to.send("You have everything you need! Well done! You can keep passing resources and talking with your 'neighbors' if you like. Just make sure to keep the resources that you need!") else: await u_to.send(f"You now have {self.assignments[u_to]['has']} and you need {self.assignments[u_to]['needs']}") for o in self.observers: await o.send(f"{message.author.name} sent {resource} to {u_to.name}") if finished: await o.send(f"{u_to.name} has everything they need!!!") else: await message.author.send(f"Resource not sent. Are you sure you have {resource}?") def is_finished(self, u_to): if set(self.assignments[u_to]['needs']) <= set(self.assignments[u_to]['has']): return True return False def give_resource(self, resource, u_from, u_to): if resource not in self.assignments[u_from]['has']: return False else: self.assignments[u_from]['has'].remove(resource) self.assignments[u_to]['has'].append(resource) return True def get_assignments(student_list, edgelist = './network_game/edgelist.csv', resource_prefix = './network_game/resources_' ): def _add_connection(node1, node2): node1 = int(node1) node2 = int(node2) for i in range(len(mapping[node1])): s1 = mapping[node1][i] s2 = mapping[node2][i] if s1 in assignments: assignments[s1]['neighbors'].append(s2) else: assignments[s1] = {'neighbors': [s2]} def _add_resources(): fn = f"{resource_prefix}{group_size}.csv" with open(fn, 'r') as f: i = 1 for line in f.readlines(): resources = line.strip().split(',') curr_students = mapping[i] for s in curr_students: assignments[s]['has'] = resources[:3] assignments[s]['needs'] = resources[3:] i += 1 assignments = {} group_size = _get_group_size(len(student_list)) if len(student_list) < group_size: return None mapping = _make_mapping(student_list, group_size) with open(edgelist, 'r') as f: for line in f.readlines(): node1, node2 = line.strip().split(',') if int(node2) <= group_size: _add_connection(node1, node2) _add_connection(node2, node1) _add_resources() return assignments def _make_mapping(students, group_size): random.shuffle(students) n_observers = len(students) % group_size mapping = {} if n_observers > 0: mapping['observers'] = students[-n_observers:] for i, student in enumerate(students[-n_observers:]): j = i % group_size idx = j + 1 if idx in mapping: mapping[idx].append(student) else: mapping[idx] = [student] return mapping def _get_group_size(n): min_observers = None for x in range(7,10): observers = n % x if min_observers is None or observers < min_observers: best_fit = x min_observers = observers return best_fit # this is necessary to get information about who is online intents = discord.Intents.default() intents.members = True intents.presences = True ccb = ColdCallBot(intents=intents) ccb.run(config.key)