2020-06-26 03:04:11 -04:00
#!/usr/bin/env python3
import asyncio
import discord
import json
import random
import sys
def matchings ( l ) :
if len ( l ) == 0 :
return [ ]
l = l . copy ( )
random . shuffle ( l )
center = l . pop ( )
result = [ ]
for i in range ( len ( l ) ) :
matching = [ ( center , l [ i ] ) ]
2020-06-26 17:51:49 -04:00
for j in range ( 1 , ( len ( l ) - 1 ) / / 2 + 1 ) :
2020-06-26 03:04:11 -04:00
matching . append ( ( l [ ( i - j ) % len ( l ) ] , l [ ( i + j ) % len ( l ) ] ) )
result . append ( matching )
return result
async def delete_if_possible ( channels ) :
for c in channels :
try :
await c . delete ( )
except :
pass
with open ( ' config.json ' ) as f :
config = json . load ( f )
client = discord . Client ( )
@client.event
async def on_ready ( ) :
print ( ' logged in as {0.user} ' . format ( client ) , file = sys . stderr )
@client.event
async def on_message ( message ) :
if message . author == client . user :
return
if not message . content . startswith ( ' !waggle ' ) :
return
if not message . author . guild_permissions . administrator :
await message . channel . send ( ' only administrators can start pollination! ' )
return
argv = message . content . split ( )
if len ( argv ) > 1 :
try :
rounds = int ( message . content . split ( ) [ 1 ] )
except ValueError :
2020-06-26 04:13:03 -04:00
await message . channel . send ( " usage: `!waggle 6` for at most 6 rounds of pollination, `!waggle` for as many rounds as possible until everyone ' s met everyone else " )
2020-06-26 03:04:11 -04:00
return
else :
rounds = None
voice_state = message . author . voice
if voice_state is None or voice_state . channel is None :
await message . channel . send ( ' you need to be in the main gathering voice channel to start pollination ' )
return
main_voice_channel = voice_state . channel
category = message . channel . category
if category is None :
await message . channel . send ( " please re-send this message in a channel in the category where you ' d like me to create voice channels " )
return
participants = main_voice_channel . members . copy ( )
if len ( participants ) % 2 != 0 :
participants . remove ( message . author )
await message . channel . send ( ' leaving out {} so we have an even number of participants ' . format ( message . author . mention ) )
if len ( participants ) == 0 :
await message . channel . send ( ' there are no participants! :( ' )
return
mention_all = ' ' . join ( u . mention for u in participants )
schedule = matchings ( participants )
if rounds :
schedule = schedule [ : rounds ]
pollination_channels = [ ]
channel_names = config [ ' channel_names ' ] . copy ( )
exception_count = 0
2020-06-26 17:51:49 -04:00
while len ( pollination_channels ) < len ( participants ) / / 2 :
2020-06-26 03:04:11 -04:00
if len ( channel_names ) > 0 :
name = channel_names . pop ( 0 )
else :
name = ' pollination- {} ' . format ( random . randrange ( 10000 ) )
try :
pollination_channels . append ( await category . create_voice_channel ( name ) )
exception_count = 0
except discord . Forbidden :
await message . channel . send ( " looks like I ' m not allowed to create voice channels :( " )
await delete_if_possible ( pollination_channels )
return
except discord . HTTPException as e :
exception_count + = 1
if exception_count > 20 :
await message . channel . send ( " I ' m trying to create voice channels, but something ' s wrong: {} " . format ( e ) )
await delete_if_possible ( pollination_channels )
return
continue
2020-06-26 03:37:20 -04:00
await message . channel . send ( " {} Welcome to pollination! You ' ll be randomly paired up, moved into separate voice channels, spend some time chatting, and then move to a new channel and meet somebody else. Each round will last 5 minutes, and there ' ll be {} rounds total. I ' ll announce when your time is nearly up so you can wrap up your conversations, and I ' ll automatically move you to a different voice channel at the start of each new round. **Feel free to leave at any time if you need to. You won ' t get moved into new voice channels if you disconnect from voice.** If you find yourself alone in a channel, the person you were paired with for that round may have left; just relax and take a break for 5 minutes. Have fun! " . format ( mention_all , len ( schedule ) ) )
2020-06-26 03:04:11 -04:00
for matching in schedule :
2020-06-26 03:37:20 -04:00
announcement = ' Next round starting in 30 seconds: \n '
2020-06-26 03:04:11 -04:00
announcement + = ' \n ' . join ( ' {0} and {1} in {2} ' . format ( a . mention , b . mention , c . name ) for ( ( a , b ) , c ) in zip ( matching , pollination_channels ) )
await message . channel . send ( announcement )
await asyncio . sleep ( 30 )
for ( ( a , b ) , c ) in zip ( matching , pollination_channels ) :
try :
await a . move_to ( c )
except e :
2020-06-26 03:37:20 -04:00
print ( ' failed to move participant {} : {} ' . format ( a , e ) , file = sys . stderr )
2020-06-26 03:04:11 -04:00
try :
await b . move_to ( c )
except e :
2020-06-26 03:37:20 -04:00
print ( ' failed to move participant {} : {} ' . format ( b , e ) , file = sys . stderr )
2020-06-26 03:04:11 -04:00
await asyncio . sleep ( 60 * 3 )
2020-06-26 03:37:20 -04:00
await message . channel . send ( ' Round ending in 2 minutes {} ' . format ( mention_all ) )
2020-06-26 03:04:11 -04:00
await asyncio . sleep ( 60 )
2020-06-26 03:37:20 -04:00
await message . channel . send ( ' Round ending in 1 minute {} ' . format ( mention_all ) )
2020-06-26 03:04:11 -04:00
await asyncio . sleep ( 30 )
2020-06-26 03:37:20 -04:00
await message . channel . send ( ' Returning to main channel in 30 seconds {} ' . format ( mention_all ) )
2020-06-26 03:04:11 -04:00
await asyncio . sleep ( 30 )
for u in participants :
try :
await u . move_to ( main_voice_channel )
except e :
2020-06-26 03:37:20 -04:00
print ( ' failed to move participant {} : {} ' . format ( u , e ) , file = sys . stderr )
2020-06-26 03:04:11 -04:00
await delete_if_possible ( pollination_channels )
client . run ( config [ ' token ' ] )