#!/bin/env python import botlib from time import sleep from random import randint, choice, shuffle import re from copy import copy NAME = "dee" ### "AI" ### def send(msg): global NAME botlib.send(f'{NAME}: {msg}') def help(nick): send(f'{nick}, my commands are: "dee, roll ", "dee, shuf[fle] , , and ", and "dee, pick , , or "') def handle_msg(nick, line, words, pwords): global NAME print(nick, line, words, pwords) if not botlib.strip_direct_address(NAME, [], words, pwords): return cmd = pwords[0] pwords.pop(0) words.pop(0) if cmd == 'help': help(nick) elif len(pwords) < 1: send(f'{nick}, {cmd} what?') elif cmd == 'roll': dice(nick, words, pwords) elif cmd == 'pick': pick(nick, words, pwords) elif cmd in ('shuf', 'shuffle'): shuf(nick, words, pwords) else: send(f'{nick}, I would, if I knew how!') def handle_action(line, words, pwords): pass ### CHOICES, CHOICES ### def pick(nick, words, pwords): terms = botlib.split_list(words, pwords) picked = choice(terms) send(f'{nick}, how about {" ".join(picked)}?') def shuf(nick, words, pwords): terms = botlib.split_list(words, pwords) shuffle(terms) send(f'{nick}: {", ".join(map(" ".join, terms))}') ### DICE ### class DiceParseException(Exception): pass def parse_number(word): return int(word) ''' dice = 'then'? spec offset? spec = 'another' num? 'more'? spec = 'another'? num? 'more'? size spec = 'another'? num 'more' size = 'd' num offset = op num op = 'plus' | 'minus' | '+' | '-' num = int() or human-readable number ''' last_dice = 6 last_line = ['1', 'd6'] def parse_dice(nick, words): global last_dice, last_line if words[0] == 'then': words.pop(0) if len(words) == 0: return 0, 0, 0 if words[0] == 'again': return parse_dice(nick, last_line) else: last_line = copy(words) has_another = False if words[0] == 'another': has_another = True words.pop(0) if len(words) == 0: return 1, last_dice, 0 can_more = True try: count = parse_number(words[0]) words.pop(0) except (IndexError, ValueError): count = 1 can_more = False if len(words) == 0: if has_another: return count, last_dice, 0 else: raise DiceParseException(f'roll {count} what?') if d := re.match('d([0-9]+|[A-Za-z]+)', words[0]): last_dice = parse_number(d.group(1)) words.pop(0) if len(words) > 0 and words[0] == 'more': words.pop(0) if len(words) == 0: return count, last_dice, 0 elif words[0] == 'more': if not can_more: raise DiceParseException(f'roll how many more d{last_dice}?') words.pop(0) if len(words) == 0: return count, last_dice, 0 if words[0] in ('plus', 'add', '+', 'minus', 'sub', 'subtract', '-'): try: offset = parse_number(words[1]) except (IndexError, ValueError): raise DiceParseException(f'{words[0]} what?') if words[0] not in ('plus', 'add', '+'): offset *= -1 return count, last_dice, offset raise DiceParseException(f'what?') def dice(nick, words, pwords): result = nick terms = botlib.split_list(words, pwords) print(f'{terms=}') for term in terms: try: count, size, offset = parse_dice(nick, term) except DiceParseException as e: send(f'{nick}, {e.args[0]}') return if count == 0: continue if count > 50: send(f'{nick}, roll them yourself!') return rollsum = offset # string formatting if count == 1: result += f', 1 d{size}' else: result += f', {count} d{size}s' if offset > 0: offset = f' + {offset}' elif offset < 0: offset = f' - {-offset}' else: offset = '' result += f'{offset}:' for i in range(count): if size < 1: roll = size else: roll = randint(1, size) rollsum += roll if i > 0: result += f' + {roll}' else: result += f' {roll}' if count > 1 or offset != '': result += f'{offset} = {rollsum}' if size == 0: result += ', obviously' if result == nick: send(f'{nick}, done, i guess') elif len(result) < 100: send(result) else: send(f'{nick}, roll them yourself!') ### BOOT ### botlib.parse_args() while True: sleep(5) botlib.writeln(f"SKIP {botlib.lastmsg}") lines = botlib.readmany() for line in lines: print(line) botlib.handle_line(line, NAME, handle_msg, handle_action)