forked from zgrep/happybot
144 lines
4.1 KiB
Python
Executable file
144 lines
4.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
from subprocess import Popen, PIPE
|
|
import re
|
|
|
|
def cmd(args):
|
|
proc = Popen(args, stdout=PIPE)
|
|
while True:
|
|
line = proc.stdout.readline()
|
|
if line:
|
|
try:
|
|
yield str(line[:-1], 'utf-8', 'ignore')
|
|
except:
|
|
pass
|
|
else:
|
|
break
|
|
|
|
def irc(chan):
|
|
global trigger
|
|
fdir = '/home/zgrep/offtopiabday/irc.freenode.net/' + chan
|
|
fin = fdir + '/in'
|
|
fout = fdir + '/out'
|
|
|
|
for line in cmd(['tail', '-n', '0', '-f', fout]):
|
|
date, time, nick, line = line.split(' ', 3)
|
|
print(line)
|
|
m = re.match(r'(?i)(?:happy|hate)bot[:,]\s+([0-9]+)\s+(fractrand?)\s+([0-9]+/[0-9]+(?:,?\s+[0-9]+/[0-9]+)*)$', line)
|
|
if m:
|
|
n, f, fs = m.group(1), m.group(2), m.group(3)
|
|
print('Matched!', n, f, fs)
|
|
trigger = True
|
|
r = doit(f, n, fs)
|
|
trigger = False
|
|
r = '\u200b' + r
|
|
print('Result!', r)
|
|
with open(fin, 'w') as fh:
|
|
fh.write(r + '\n')
|
|
|
|
from fractions import Fraction
|
|
from random import choice
|
|
import signal
|
|
|
|
trigger = False
|
|
|
|
class TimeoutException(Exception): pass
|
|
def signal_handler(signum, frame):
|
|
global trigger
|
|
if trigger:
|
|
raise TimeoutException("Timed out!")
|
|
|
|
def fractran(n, fracs):
|
|
vals = [n]
|
|
signal.alarm(1)
|
|
try:
|
|
while True:
|
|
for frac in fracs:
|
|
n2 = n*frac
|
|
if n2.denominator == 1:
|
|
n = n2.numerator
|
|
if n in vals:
|
|
i = vals.index(n)
|
|
return 'Infinite loop: ..., ' + ', '.join(map(str, vals[i:]))
|
|
vals.append(n)
|
|
break
|
|
else:
|
|
if len(vals) > 12:
|
|
beg = ', '.join(map(str, vals[:2]))
|
|
end = ', '.join(map(str, vals[-10:]))
|
|
return f'{beg}, ..., {end}'
|
|
else:
|
|
return ', '.join(map(str, vals))
|
|
except TimeoutException:
|
|
if len(vals) > 12:
|
|
beg = ', '.join(map(str, vals[:10]))
|
|
end = ', '.join(map(str, vals[-2:]))
|
|
return f'Timed out: {beg}, ..., {end}, ...'
|
|
else:
|
|
return 'Timed out: ', + ', '.join(map(str, vals))
|
|
|
|
def random_unordered_fractran(n, fracs):
|
|
vals = [n]
|
|
signal.alarm(1)
|
|
try:
|
|
while True:
|
|
ns = [ n * frac for frac in fracs ]
|
|
ns = [ m for m in ns if m.denominator == 1 ]
|
|
if not ns:
|
|
if len(vals) > 12:
|
|
beg = ', '.join(map(str, vals[:2]))
|
|
end = ', '.join(map(str, vals[-10:]))
|
|
return f'{beg}, ..., {end}'
|
|
else:
|
|
return ', '.join(map(str, vals))
|
|
n = choice(ns)
|
|
vals.append(n)
|
|
except TimeoutException:
|
|
if len(vals) > 12:
|
|
beg = ', '.join(map(str, vals[:10]))
|
|
end = ', '.join(map(str, vals[-2:]))
|
|
return f'Timed out: {beg}, ..., {end}, ...'
|
|
else:
|
|
return 'Timed out: ', + ', '.join(map(str, vals))
|
|
|
|
def main():
|
|
from sys import argv
|
|
if len(argv) == 2:
|
|
# IRC mode.
|
|
irc(argv[1])
|
|
elif len(argv) == 4:
|
|
# cli mode.
|
|
print(doit(argv[1], argv[2], argv[3]))
|
|
else:
|
|
print('Wrong number of arguments.')
|
|
exit(1)
|
|
|
|
def doit(func, inp, args):
|
|
n, fracs = None, None
|
|
try:
|
|
n = int(inp)
|
|
except:
|
|
return 'Input is not an integer?'
|
|
try:
|
|
fracs = [Fraction(*map(int, x.split('/', 1))) for x in args.replace(',', '').split()]
|
|
except:
|
|
return 'Could not parse fraction list.'
|
|
|
|
if func == 'fractran':
|
|
func = fractran
|
|
elif func == 'fractrand':
|
|
func = random_unordered_fractran
|
|
else:
|
|
return f'Invalid function: {func}'
|
|
|
|
signal.signal(signal.SIGALRM, signal_handler)
|
|
try:
|
|
return func(n, fracs)
|
|
except TimeoutException:
|
|
return 'Timed out.'
|
|
except Exception as e:
|
|
return 'Some error occurred: ' + str (e)
|
|
return 'Something went wrong.'
|
|
|
|
if __name__ == '__main__':
|
|
main()
|