Compare commits
2 Commits
flask
...
foote_spri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46796e647a | ||
|
|
788ed2de62 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
*~
|
||||
__pycache__
|
||||
config.py
|
||||
|
||||
2
README
2
README
@@ -18,7 +18,7 @@ the steps there, with one important exception:
|
||||
need to enable both "Privileged Gateway Intents." This allows the bot
|
||||
to see who is present and active in the channel.
|
||||
|
||||
Finally, you need to copy your bot'ss Token (also found on the "Bot" tab)
|
||||
Finally, you need to copy your bot's Token (also found on the "Bot" tab)
|
||||
into coldcallbot.py. Pass it as the argument to `ccb.run()`.
|
||||
|
||||
|
||||
|
||||
24
coldcall.py
24
coldcall.py
@@ -11,22 +11,26 @@ import re
|
||||
import discord
|
||||
|
||||
class ColdCall():
|
||||
def __init__ (self):
|
||||
def __init__ (self, course = ''):
|
||||
self.course = course
|
||||
self.today = str(datetime.date(datetime.now()))
|
||||
# how much less likely should it be that a student is called upon?
|
||||
self.weight = 2
|
||||
self.weight = 2
|
||||
self.__set_filenames()
|
||||
|
||||
|
||||
def __set_filenames(self):
|
||||
# filenames
|
||||
self.__fn_studentinfo = "data/student_information.tsv"
|
||||
self.__fn_daily_calllist = f"data/call_list-{self.today}.tsv"
|
||||
self.__fn_daily_attendance = f"data/attendance-{self.today}.tsv"
|
||||
self.__fn_studentinfo = f"data/{self.course}/student_information.tsv"
|
||||
self.__fn_daily_calllist = f"data/{self.course}/call_list-{self.today}.tsv"
|
||||
self.__fn_daily_attendance = f"data/{self.course}/attendance-{self.today}.tsv"
|
||||
|
||||
def __load_prev_questions(self):
|
||||
previous_questions = defaultdict(int)
|
||||
|
||||
for fn in listdir("./data/"):
|
||||
for fn in listdir(f"./data/{self.course}/"):
|
||||
if re.match("call_list-\d{4}-\d{2}-\d{2}.tsv", fn):
|
||||
with open(f"./data/{fn}", 'r') as f:
|
||||
with open(f"./data/{self.course}/{fn}", 'r') as f:
|
||||
for row in DictReader(f, delimiter="\t"):
|
||||
if not row["answered"] == "FALSE":
|
||||
previous_questions[row["discord_name"]] += 1
|
||||
@@ -40,7 +44,7 @@ class ColdCall():
|
||||
preferred_names = {}
|
||||
with open(self.__fn_studentinfo, 'r') as f:
|
||||
for row in DictReader(f, delimiter="\t"):
|
||||
preferred_names[row["Your username on the class Discord server"]] = row["Name you'd like to go by in class"]
|
||||
preferred_names[row["discord_name"]] = row["name"]
|
||||
|
||||
if selected_student in preferred_names:
|
||||
return preferred_names[selected_student]
|
||||
@@ -99,6 +103,10 @@ class ColdCall():
|
||||
coldcall_message = f"@{selected_student}, you're up!"
|
||||
return coldcall_message
|
||||
|
||||
def update_course(self, course_name):
|
||||
self.course = course_name
|
||||
self.__set_filenames()
|
||||
|
||||
# cc = ColdCall()
|
||||
|
||||
# test_student_list = ["jordan", "Kristen Larrick", "Madison Heisterman", "Maria.Au20", "Laura (Alia) Levi", "Leona Aklipi", "anne", "emmaaitelli", "ashleylee", "allie_partridge", "Tiana_Cole", "Hamin", "Ella Qu", "Shizuka", "Ben Baird", "Kim Do", "Isaacm24", "Sam Bell", "Courtneylg"]
|
||||
|
||||
164
coldcallbot.py
164
coldcallbot.py
@@ -3,6 +3,8 @@
|
||||
from coldcall import ColdCall
|
||||
import re
|
||||
import discord
|
||||
import config
|
||||
import random
|
||||
|
||||
## create the coldcall object
|
||||
cc = ColdCall()
|
||||
@@ -11,13 +13,16 @@ 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):
|
||||
async def on_message(self, message, voice_channel = 'Class Sessions'):
|
||||
if message.author == self.user:
|
||||
return
|
||||
|
||||
if message.content.startswith('$next'):
|
||||
classroom = discord.utils.get(message.guild.voice_channels, name='Classroom Voice')
|
||||
|
||||
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]:
|
||||
@@ -30,8 +35,156 @@ class ColdCallBot (discord.Client):
|
||||
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()
|
||||
@@ -39,5 +192,4 @@ intents.members = True
|
||||
intents.presences = True
|
||||
|
||||
ccb = ColdCallBot(intents=intents)
|
||||
ccb.run('CHANGEME')
|
||||
|
||||
ccb.run(config.key)
|
||||
|
||||
3
update_student_info.sh
Executable file
3
update_student_info.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
wget "https://docs.google.com/spreadsheets/d/e/2PACX-1vTBboNsATMKYdQM3WsbcIvloqRlvR9ajSgZWyHN6Bci50wfiPBjibTxaF8XcMgAJycvKNdAfR9LBHbp/pub?gid=1302288840&single=true&output=csv" -O ./data/COM\ 495\ -\ Turning\ Data\ into\ Insights\ and\ Stories/student_information.tsv
|
||||
|
||||
wget "https://docs.google.com/spreadsheets/d/e/2PACX-1vSPL6jKD2rXQqac6O0pMb4JRxMAOM-EdPkZw2FuebbJHiZdAl4n5Df5RCyuxoHcwOcW0VbBevnec6b-/pub?gid=1575299441&single=true&output=csv" -O ./data/COM\ 411\ -\ Communication\ and\ Social\ Networks/student_information.tsv
|
||||
Reference in New Issue
Block a user