happybot/rfk/rfk.py

314 lines
9.3 KiB
Python

#!/usr/bin/env python3
from subprocess import Popen, PIPE
from random import choice, random
from time import sleep
from os import chdir
map_url = 'https://zgrep.org/taxreturns/rfk.txt'
# Log.
def logging(msg):
with open('log.txt', 'a') as fh:
fh.write(msg.strip() + '\n')
# Items.
def get_items():
with open('rfk.txt') as fh:
return [l.strip() for l in fh]
def add_item(item):
items = set(get_items() + [item])
with open('rfk.txt', 'w') as fh:
fh.write('\n'.join(items) + '\n')
logging('add item: ' + item)
return 'Added item: ' + item
def del_item(item):
items = set(get_items())
if item in items:
items.remove(item)
with open('rfk.txt', 'w') as fh:
fh.write('\n'.join(items) + '\n')
logging('del item: ' + item)
return 'Removed item: ' + item
else:
removal = None
for maybe in items:
if maybe.lower().startswith(item.lower()):
if removal:
break
else:
removal = maybe
else:
if removal:
items.remove(removal)
with open('rfk.txt', 'w') as fh:
fh.write('\n'.join(items) + '\n')
logging('del item: ' + removal)
return 'Removed item: ' + removal
else:
return 'No items matched: ' + item
return 'More than one item matched: ' + item
# Robot finds kitten bits below.
grid = {}
width, height = 30, 15
rx, ry = width // 2, height // 2
percent = 0.1
blind = False
found = False
def string(): # prints the grid as a string
global grid, rx, ry, width, height, found
result = ''
for y in range(height):
for x in range(width):
if (x, y) in grid:
item = grid[(x, y)]
if found and item[2]:
result += 'K'
else:
result += item[0]
elif x == rx and y == ry:
result += '#'
else:
result += ' '
result += '\n'
return result
def move(x, y): # teleports to location
global rx, ry, width, height, grid, found
if x < 0 or y < 0 or x >= width or y >= height:
return 'There is a wall in the way.'
elif (x, y) in grid:
result = grid[(x, y)]
if result[2]:
found = True
return result[1]
else:
rx, ry = x, y
return None
up = lambda: move(rx, ry - 1)
down = lambda: move(rx, ry + 1)
left = lambda: move(rx - 1, ry)
right = lambda: move(rx + 1, ry)
symbols = '~!@$%^&*()`[]{}=+\\/?|-_;:\'"<>,.abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def reset(): # Set up a new game.
global width, height, rx, ry, grid, percent, found
grid = {}
found = False
items = get_items()
rx, ry = width // 2, height // 2
for y in range(height):
for x in range(width):
if random() <= percent and x != rx and y != ry:
grid[(x, y)] = (choice(symbols), choice(items), False)
if not grid:
kitten = (rx - 2, ry - 2)
else:
kitten = choice(list(grid))
with open('found.txt') as fh:
messages = [f.strip('\n') for f in fh.read().strip('\n').split('\n%\n')]
grid[kitten] = (choice(symbols), choice(messages), True)
if len(grid) == 1:
objects = 'there is 1 object'
else:
objects = 'there are {} objects'.format(len(grid))
if not blind:
append = 'Map: ' + map_url
else:
append = 'No map is being made, blind is set to true.'
return 'New game! The grid is {} by {}, and {}. You are in the center. {}'\
.format(width, height, objects, append)
# Parsing input.
def tofile():
global blind
if not blind:
with open('/home/zgrep/tax/rfk.txt', 'w') as fh:
fh.write(string())
def dedup(gen):
prev = None
for item in gen:
if item == prev:
continue
else:
prev = item
yield item
def parse(cmd, normalcase):
global width, height, percent, blind
if all(c in 'udlrnsew^v<>←↑→↓' for c in cmd):
for c in cmd:
if c in 'u^n↑':
yield up()
elif c in 'dvs→':
yield down()
elif c in 'l<w←':
yield left()
elif c in 'r>e↓':
yield right()
tofile()
elif cmd in ('up', 'north'):
yield up()
tofile()
elif cmd in ('down', 'south'):
yield down()
tofile()
elif cmd in ('left', 'west'):
yield left()
tofile()
elif cmd in ('right', 'east'):
yield right()
tofile()
elif cmd.startswith('size '):
cmd = cmd.replace('size ', '', 1)
try:
w, h = map(int, cmd.split('x'))
w = min(max(w, 5), 1000)
h = min(max(h, 5), 1000)
width, height = w, h
yield reset()
tofile()
yield topic()
except:
yield 'The correct format for size is 10x10.'
elif cmd.startswith('blind '):
cmd = cmd.replace('blind ', '', 1)
if ' ' not in cmd:
if cmd in ('true', 'yes', 'on', '1'):
blind = True
with open('/home/zgrep/tax/rfk.txt', 'w') as fh:
fh.write('Blind is turned on, no map is being generated.\n')
yield topic()
yield 'Blind has been set to true, no new maps with be generated.'
elif cmd in ('false', 'no', 'off', '0'):
blind = False
tofile()
yield topic()
yield 'Blind has been turned off, a map has been generated: ' + map_url
else:
yield 'Expected either true or false.'
elif cmd.startswith('prob '):
cmd = cmd.replace('prob ', '', 1)
try:
m = 1
if cmd[-1] == '%':
cmd = cmd[:-1]
m = 0.01
p = min(max(m*float(cmd), 0), 1)
percent = p
yield reset()
tofile()
yield topic()
except:
yield 'The correct format for prob is 0.1 or 10%.'
elif cmd.startswith('add item '):
yield add_item(normalcase[9:])
elif cmd.startswith('del item '):
yield del_item(normalcase[9:])
elif cmd in ('reset', 'new game', 'restart'):
yield reset()
tofile()
yield topic()
elif cmd == 'help':
yield 'Commands: size, prob, add item, del item, up (north), down (south), left (west), right (east), new game, blind, map, help.'
yield '^<>vudlrnsew becomes up left right down up down left right north south east west. Only the one-character short commands can be chained together in one IRC message.'
if not blind:
yield 'A map of the grid can be found at: {}'.format(map_url)
else:
yield 'Currently blind is set to true, and therefore no map of the grid is generated. But normally, it would be found here: {}'.format(map_url)
elif cmd in ('map', 'grid'):
yield map_url
elif cmd == 'size':
yield '{} by {}'.format(width, height)
elif cmd == 'prob':
s = 's'
if len(grid) == 1: s = ''
yield '{}%, with {} object{} on the current grid.'\
.format(percent*100, len(grid), s)
elif cmd == 'blind':
yield ('blind is set to false, a map is being generated.',
'blind is set to true, no map is being generated.')[blind]
# IRC-specific bits below.
def topic():
global found, width, height, grid
s = 's'
if len(grid) == 1: s = ''
append = 'No map.'
if not blind:
append = 'Map: ' + map_url
finding = ''
if found is True:
finding = ' Kitten has been found!'
elif found:
finding = ' Kitten has been found by {}!'.format(found)
return '/t Robot finds kitten. To play, type "help". | The grid is {} by {}, and has {} object{}.{} {}'\
.format(width, height, len(grid), s, finding, append)
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 begin(fin, fout):
global found
fin = '/home/zgrep/offtopiabday/' + fin
fout = '/home/zgrep/offtopiabday/' + fout
def send(msg):
if msg:
with open(fin, 'w') as fh:
fh.write(msg.strip() + '\n')
send(reset())
tofile()
send(topic())
for line in cmd(['tail', '-n', '0', '-f', fout]):
_, _, nick, line = line.split(' ', 3)
nick = nick[1:-1]
if nick in ('happybot', 'hatebot'):
continue
output = list(dedup(parse(line.lower(), line)))
if found is True:
found = nick
with open('finders.txt', 'a') as fh:
fh.write(found + '\n')
send(topic())
time = 0
if len(output) > 3:
time = 0.5
for line in output:
send(line)
sleep(time)
from sys import argv
if len(argv) != 3:
print('Usage: in out')
exit(1)
chdir('/home/zgrep/offtopiabday/rfk')
begin(*argv[1:])