Add files I forgot
This commit is contained in:
parent
5f1bf146c3
commit
772995c0ff
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import argparse
|
||||
from pinhook.bot import Bot
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--server",
|
||||
dest="server",
|
||||
default="127.0.0.1",
|
||||
help="the server to connect to",
|
||||
metavar="SERVER",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--port",
|
||||
dest="port",
|
||||
type=int,
|
||||
default=6667,
|
||||
help="the port to connect to",
|
||||
metavar="PORT",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--channels",
|
||||
dest="channels",
|
||||
nargs="+",
|
||||
default=["#bot_test"],
|
||||
help="the channels to join",
|
||||
metavar="CHANNELS",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--nick",
|
||||
dest="nick",
|
||||
default="banterbot",
|
||||
help="the nick to use",
|
||||
metavar="NICK",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o",
|
||||
"--owner",
|
||||
dest="owner",
|
||||
default="krowbar",
|
||||
help="the owner of this bot",
|
||||
metavar="OWNER",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
print(args)
|
||||
|
||||
bot = Bot(
|
||||
channels = args.channels,
|
||||
nickname = args.nick,
|
||||
ops = [ args.owner ],
|
||||
plugin_dir = "{}_plugins".format(args.nick),
|
||||
server = args.server,
|
||||
port = args.port
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
bot.start()
|
|
@ -0,0 +1 @@
|
|||
../util.py
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import pinhook.plugin
|
||||
|
||||
@pinhook.plugin.register('!rollcall')
|
||||
def rollcall_plugin(msg):
|
||||
return pinhook.plugin.message("tildebot reporting! I respond to !tilde !tildescore")
|
|
@ -0,0 +1,41 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import pinhook.plugin
|
||||
import util.tilde
|
||||
|
||||
@pinhook.plugin.register('!tildescore')
|
||||
def tildescore_plugin(msg):
|
||||
return pinhook.plugin.message(util.tilde.show_tildescore(msg.nick))
|
||||
|
||||
@pinhook.plugin.register('!jackpot')
|
||||
def jackpot_plugin(msg):
|
||||
return pinhook.plugin.message(util.tilde.show_jackpot())
|
||||
|
||||
# ADMIN PLUGIN
|
||||
@pinhook.plugin.register('!debug')
|
||||
def debug_plugin(msg):
|
||||
if msg.nick not in msg.ops:
|
||||
return
|
||||
if msg.arg:
|
||||
util.tilde.DEBUG = (msg.arg.lower == 'true' or msg.arg.lower == 't')
|
||||
return pinhook.plugin.message("DEBUG set to '{}'".format(util.tilde.DEBUG))
|
||||
|
||||
# ADMIN PLUGIN
|
||||
@pinhook.plugin.register('!tilde_requests')
|
||||
def tilde_requests_plugin(msg):
|
||||
if msg.nick not in msg.ops and not util.tilde.DEBUG:
|
||||
return
|
||||
return pinhook.plugin.message("Outstanding requests: {}".format(",".join(util.tilde.challenges) if util.tilde.challenges else "(none)"))
|
||||
|
||||
@pinhook.plugin.register('!tilde')
|
||||
def tilde_plugin(msg):
|
||||
if msg.channel != util.tilde.GOOD_CHAN and not util.tilde.DEBUG:
|
||||
return pinhook.plugin.message("{} is a meanie and gets no tildes. **Tildebot now only gives out tildes in the {} channel.**".format(msg.nick, util.tilde.GOOD_CHAN))
|
||||
if msg.nick not in util.tilde.challenges:
|
||||
return pinhook.plugin.message(util.tilde.challenge(msg.channel, msg.nick, msg.timestamp))
|
||||
|
||||
@pinhook.plugin.listener('tilde_guess')
|
||||
def tilde_guess_plugin(msg):
|
||||
if msg.nick in util.tilde.challenges and (msg.channel == util.tilde.GOOD_CHAN or util.tilde.DEBUG):
|
||||
return pinhook.plugin.message(util.tilde.challenge_response(msg.nick, msg.timestamp, msg.text))
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import pinhook.plugin
|
||||
from util import topic
|
||||
|
||||
import inflect
|
||||
|
||||
@pinhook.plugin.listener('topic')
|
||||
def topic_listener(msg):
|
||||
if msg.text.startswith("TOPIC"):
|
||||
topic.count_topic(msg.channel, msg.nick, msg.time, msg.text)
|
||||
|
||||
@pinhook.plugin.register('!topic')
|
||||
def topic_plugin(msg):
|
||||
return pinhook.plugin.message(topic.get_topic(msg.channel, msg.nick, msg.time))
|
||||
|
||||
@pinhook.plugin.register('!settopic')
|
||||
def set_topic_plugin(msg):
|
||||
return pinhook.plugin.action("TOPIC {} {}".format(msg.channel, msg.arg))
|
||||
|
||||
@pinhook.plugin.register('!randomtopic')
|
||||
def set_topic_plugin(msg):
|
||||
return pinhook.plugin.message(topic.random_topic(msg.channel, msg.nick, msg.time, msg.nick == msg.owner))
|
||||
|
||||
@pinhook.plugin.register('!suggesttopic')
|
||||
def suggest_topic_plugin(msg):
|
||||
return pinhook.plugin.message(topic.random_topic(msg.channel, msg.nick, msg.time, False))
|
||||
|
||||
@pinhook.plugin.register('!thistory')
|
||||
def topic_history_plugin(msg):
|
||||
return pinhook.plugin.message(topic.topic_history(msg.channel, msg.nick, msg.arg))
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/python3
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import random
|
||||
import string
|
||||
|
||||
dict = "/usr/share/dict/american-english"
|
||||
(userId, token) = open("/home/krowbar/.secret/s4token").readline().rstrip().split(",")
|
||||
|
||||
|
||||
def get_acros(word, silly, short):
|
||||
acros = []
|
||||
url = "http://www.stands4.com/services/v2/abbr.php?uid={}&tokenid={}&term={}".format(
|
||||
userId, token, word
|
||||
)
|
||||
soup = BeautifulSoup(requests.get(url).content, "html5lib")
|
||||
results = soup.find_all("result")
|
||||
# there are lots of cases where the same definition is repeated multiple times under different categories. this is dumb so we should do a little more work
|
||||
defs = []
|
||||
for r in results:
|
||||
rdef = r.find("definition").text
|
||||
match = next((x for x in defs if x["definition"].lower() == rdef.lower()), None)
|
||||
if match is not None:
|
||||
# if we find a match, add the category to the existing categories and increase the score
|
||||
match["categories"].append(
|
||||
(
|
||||
(r.find("parentcategoryname").text + "\\")
|
||||
if r.find("parentcategoryname")
|
||||
else ""
|
||||
)
|
||||
+ r.find("categoryname").text
|
||||
)
|
||||
match["score"] = str(float(match["score"]) + float(r.find("score").text))
|
||||
else: # add a new item
|
||||
defs.append(
|
||||
{
|
||||
"term": r.find("term").text,
|
||||
"definition": r.find("definition").text,
|
||||
"categories": [
|
||||
(
|
||||
(r.find("parentcategoryname").text + "\\")
|
||||
if r.find("parentcategoryname")
|
||||
else ""
|
||||
)
|
||||
+ r.find("categoryname").text
|
||||
],
|
||||
"score": r.find("score").text,
|
||||
}
|
||||
)
|
||||
|
||||
for d in sorted(defs, key=lambda x: float(x["score"]), reverse=True):
|
||||
# print d;
|
||||
if short is True:
|
||||
acros.append('"%s"' % d["definition"])
|
||||
else:
|
||||
acros.append(
|
||||
(
|
||||
'{}: "{}" ({}, score: {})'.format(
|
||||
d["term"],
|
||||
d["definition"],
|
||||
", ".join(d["categories"]),
|
||||
d["score"],
|
||||
)
|
||||
)
|
||||
)
|
||||
if silly is True:
|
||||
newDef = []
|
||||
words = open(dict, "r").readlines()
|
||||
try:
|
||||
for idx, letter in enumerate(word):
|
||||
newWord = random.choice(
|
||||
list(filter(
|
||||
lambda w: (idx is 0 or not w.strip().lower().endswith("'s"))
|
||||
and w.lower().startswith(letter.lower()),
|
||||
words,
|
||||
))
|
||||
).strip()
|
||||
print(str(idx) + " -> " + newWord)
|
||||
newDef.append(newWord)
|
||||
newWord = string.capwords(" ".join(newDef))
|
||||
if short is True:
|
||||
acros.append('"%s"' % newWord)
|
||||
else:
|
||||
acros.append(
|
||||
(
|
||||
'{}: "{}" ({}, score: {})'.format(
|
||||
word.upper(), newWord, "Tilde.town Original", "0"
|
||||
)
|
||||
)
|
||||
)
|
||||
except IndexError:
|
||||
acros.append("Future hazy, try again later: Tilde.town Error")
|
||||
if short is True:
|
||||
shortList = acros[0:5]
|
||||
if len(acros) > 5:
|
||||
shortList.append(acros[-1])
|
||||
return [word.upper() + ": " + ", ".join(shortList)]
|
||||
else:
|
||||
return acros
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import random
|
||||
import re
|
||||
|
||||
banter_file = "/home/krowbar/Code/irc/data/banterscores.txt"
|
||||
|
||||
def score_banter(nick, messageText):
|
||||
print(re)
|
||||
score = 5
|
||||
with open(banter_file, "r") as banterfile:
|
||||
bantz = banterfile.readlines()
|
||||
words = messageText.strip("\n").split(" ")
|
||||
for word in words:
|
||||
for bant in bantz:
|
||||
bword = bant.strip("\n").split("|")
|
||||
if re.sub("[^a-z0-9]+", "", word.lower()) == bword[0]:
|
||||
score += int(bword[1])
|
||||
|
||||
score += messageText.count("!") * 2 # hype is banter
|
||||
score -= messageText.count("!!!") * 6 # too much hype is not banter
|
||||
score += messageText.count("#") * 3 # hashs are mad bantz
|
||||
score -= messageText.count("##") * 6 # but too many is garbage
|
||||
|
||||
names = ["mate", "lad", "my best boy"]
|
||||
compliment = [
|
||||
"top-drawer",
|
||||
"top-shelf",
|
||||
"bangin'",
|
||||
"legendary",
|
||||
"smashing",
|
||||
"incredible",
|
||||
"impeccable",
|
||||
"stunning",
|
||||
]
|
||||
|
||||
msg = ""
|
||||
if score > 100:
|
||||
msg = "Truely {}, {}! That was some #banter! You earned a {} for that!".format(
|
||||
random.choice(compliment).capitalize(), random.choice(names), score
|
||||
)
|
||||
elif score > 50:
|
||||
msg = "{} #banter! You get a {} from me!".format(
|
||||
random.choice(compliment).capitalize(), score
|
||||
)
|
||||
elif score > 10:
|
||||
msg = "{} #banter. You get a {}".format(
|
||||
random.choice(["acceptible", "reasonable", "passable"]).capitalize(), score
|
||||
)
|
||||
else:
|
||||
msg = "That {} #banter, {}. I'll give you a {}. Maybe try again?".format(
|
||||
random.choice(
|
||||
["was hardly", "was barely", "wasn't", "won't pass for", "was awful"]
|
||||
),
|
||||
random.choice(["lad", "lah", "boy", "son"]),
|
||||
score,
|
||||
)
|
||||
|
||||
return msg
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/python3
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import random
|
||||
|
||||
|
||||
def define(word):
|
||||
defs = []
|
||||
url = "http://www.merriam-webster.com/dictionary/{}".format(word)
|
||||
soup = BeautifulSoup(requests.get(url).content, "html.parser")
|
||||
head = soup.find("div", id="headword")
|
||||
if head:
|
||||
for p in head.find_all("p"):
|
||||
defs.append(p.text)
|
||||
return defs
|
||||
|
||||
|
||||
key = open("/home/krowbar/.secret/key").readline().rstrip()
|
||||
|
||||
|
||||
def defWord(word, short=True):
|
||||
defs = []
|
||||
url = "http://www.dictionaryapi.com/api/v1/references/collegiate/xml/{}?key={}".format(
|
||||
word, key
|
||||
)
|
||||
soup = BeautifulSoup(requests.get(url).content, "html5lib")
|
||||
entry = soup.find("entry")
|
||||
if entry:
|
||||
for d in entry.find_all("dt"):
|
||||
defs.append(d.text)
|
||||
if short:
|
||||
return " ".join(defs)
|
||||
else:
|
||||
return defs
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/python
|
||||
import random
|
||||
import inflect
|
||||
|
||||
p = inflect.engine()
|
||||
dictionary = "/usr/share/dict/american-english-small"
|
||||
BAD_WORDS_FILE = "/home/krowbar/Code/irc/data/badwords.txt"
|
||||
|
||||
|
||||
def gen_wordlist():
|
||||
# I feel weird calling this "get_wordlist" when it's a generator without calling out that I do in fact realise it's weird - ~deltawitch
|
||||
# how about gen_wordlist
|
||||
with open(BAD_WORDS_FILE, "r") as fp:
|
||||
bad_words = set(fp)
|
||||
|
||||
for word in open(dictionary).readlines():
|
||||
if "'" not in word and word not in bad_words:
|
||||
yield word.rstrip()
|
||||
|
||||
|
||||
def get_puzzle():
|
||||
dict_words = list(gen_wordlist())
|
||||
words = random.sample(dict_words, 3)
|
||||
key = random.randrange(0, 3) # get values 1-3
|
||||
puzzle = "When alphebetized, what is the {} in {}?".format(
|
||||
p.ordinal(p.number_to_words(key + 1)), ", ".join(words)
|
||||
)
|
||||
words.sort()
|
||||
answer = words[key]
|
||||
return [answer, puzzle]
|
||||
|
||||
|
||||
def get_anagram(maxlen=6):
|
||||
dict_words = [
|
||||
word for word in gen_wordlist() if len(word) > 2 and len(word) < maxlen + 1
|
||||
]
|
||||
word = random.choice(dict_words)
|
||||
anagram = list(word)
|
||||
random.shuffle(anagram)
|
||||
anagram = "".join(anagram)
|
||||
|
||||
# Anagrams can have multiple answers, so we provide a check function that accepts all possibilities
|
||||
def answer_checker(guess):
|
||||
# Check for exact match
|
||||
if guess == word:
|
||||
return True
|
||||
# Bail out early if they didn't even use all the same letters
|
||||
if sorted(guess) != sorted(word):
|
||||
return False
|
||||
# Ok, gotta actually check if it's a word now
|
||||
return any(guess == item for item in gen_wordlist())
|
||||
|
||||
return [answer_checker, "Unscramble the following word: '{}'".format(anagram)]
|
|
@ -0,0 +1,198 @@
|
|||
import requests
|
||||
import urllib
|
||||
import json as j
|
||||
import sys
|
||||
|
||||
__version__ = 0.242
|
||||
|
||||
|
||||
def query(
|
||||
query,
|
||||
useragent="python-duckduckgo " + str(__version__),
|
||||
safesearch=True,
|
||||
html=False,
|
||||
meanings=True,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
Query DuckDuckGo, returning a Results object.
|
||||
|
||||
Here's a query that's unlikely to change:
|
||||
|
||||
>>> result = query('1 + 1')
|
||||
>>> result.type
|
||||
'nothing'
|
||||
>>> result.answer.text
|
||||
'1 + 1 = 2'
|
||||
>>> result.answer.type
|
||||
'calc'
|
||||
|
||||
Keword arguments:
|
||||
useragent: UserAgent to use while querying. Default: "python-duckduckgo %d" (str)
|
||||
safesearch: True for on, False for off. Default: True (bool)
|
||||
html: True to allow HTML in output. Default: False (bool)
|
||||
meanings: True to include disambiguations in results (bool)
|
||||
Any other keyword arguments are passed directly to DuckDuckGo as URL params.
|
||||
""" % __version__
|
||||
|
||||
safesearch = "1" if safesearch else "-1"
|
||||
html = "0" if html else "1"
|
||||
meanings = "0" if meanings else "1"
|
||||
params = {
|
||||
"q": query,
|
||||
"o": "json",
|
||||
"kp": safesearch,
|
||||
"no_redirect": "1",
|
||||
"no_html": html,
|
||||
"d": meanings,
|
||||
}
|
||||
params.update(kwargs)
|
||||
encparams = urllib.parse.urlencode(params)
|
||||
url = "http://api.duckduckgo.com/?" + encparams
|
||||
|
||||
request = requests.get(url, headers={"User-Agent": useragent})
|
||||
|
||||
return Results(request.json())
|
||||
|
||||
|
||||
class Results(object):
|
||||
def __init__(self, json):
|
||||
self.type = {
|
||||
"A": "answer",
|
||||
"D": "disambiguation",
|
||||
"C": "category",
|
||||
"N": "name",
|
||||
"E": "exclusive",
|
||||
"": "nothing",
|
||||
}.get(json.get("Type", ""), "")
|
||||
|
||||
self.json = json
|
||||
self.api_version = None # compat
|
||||
|
||||
self.heading = json.get("Heading", "")
|
||||
|
||||
self.results = [Result(elem) for elem in json.get("Results", [])]
|
||||
self.related = [Result(elem) for elem in json.get("RelatedTopics", [])]
|
||||
|
||||
self.abstract = Abstract(json)
|
||||
self.redirect = Redirect(json)
|
||||
self.definition = Definition(json)
|
||||
self.answer = Answer(json)
|
||||
|
||||
self.image = Image({"Result": json.get("Image", "")})
|
||||
|
||||
|
||||
class Abstract(object):
|
||||
def __init__(self, json):
|
||||
self.html = json.get("Abstract", "")
|
||||
self.text = json.get("AbstractText", "")
|
||||
self.url = json.get("AbstractURL", "")
|
||||
self.source = json.get("AbstractSource")
|
||||
|
||||
|
||||
class Redirect(object):
|
||||
def __init__(self, json):
|
||||
self.url = json.get("Redirect", "")
|
||||
|
||||
|
||||
class Result(object):
|
||||
def __init__(self, json):
|
||||
self.topics = json.get("Topics", [])
|
||||
if self.topics:
|
||||
self.topics = [Result(t) for t in self.topics]
|
||||
return
|
||||
self.html = json.get("Result")
|
||||
self.text = json.get("Text")
|
||||
self.url = json.get("FirstURL")
|
||||
|
||||
icon_json = json.get("Icon")
|
||||
if icon_json is not None:
|
||||
self.icon = Image(icon_json)
|
||||
else:
|
||||
self.icon = None
|
||||
|
||||
|
||||
class Image(object):
|
||||
def __init__(self, json):
|
||||
self.url = json.get("Result")
|
||||
self.height = json.get("Height", None)
|
||||
self.width = json.get("Width", None)
|
||||
|
||||
|
||||
class Answer(object):
|
||||
def __init__(self, json):
|
||||
self.text = json.get("Answer")
|
||||
self.type = json.get("AnswerType", "")
|
||||
|
||||
|
||||
class Definition(object):
|
||||
def __init__(self, json):
|
||||
self.text = json.get("Definition", "")
|
||||
self.url = json.get("DefinitionURL")
|
||||
self.source = json.get("DefinitionSource")
|
||||
|
||||
|
||||
def get_zci(
|
||||
q,
|
||||
web_fallback=True,
|
||||
priority=["answer", "abstract", "related.0", "definition"],
|
||||
urls=True,
|
||||
**kwargs
|
||||
):
|
||||
"""A helper method to get a single (and hopefully the best) ZCI result.
|
||||
priority=list can be used to set the order in which fields will be checked for answers.
|
||||
Use web_fallback=True to fall back to grabbing the first web result.
|
||||
passed to query. This method will fall back to 'Sorry, no results.'
|
||||
if it cannot find anything."""
|
||||
|
||||
ddg = query("\\" + q, **kwargs)
|
||||
response = ""
|
||||
|
||||
for p in priority:
|
||||
ps = p.split(".")
|
||||
type = ps[0]
|
||||
index = int(ps[1]) if len(ps) > 1 else None
|
||||
|
||||
result = getattr(ddg, type)
|
||||
if index is not None:
|
||||
if not hasattr(result, "__getitem__"):
|
||||
raise TypeError("%s field is not indexable" % type)
|
||||
result = result[index] if len(result) > index else None
|
||||
if not result:
|
||||
continue
|
||||
|
||||
if result.text:
|
||||
response = result.text
|
||||
if result.text and hasattr(result, "url") and urls:
|
||||
if result.url:
|
||||
response += " (%s)" % result.url
|
||||
if response:
|
||||
break
|
||||
|
||||
# if there still isn't anything, try to get the first web result
|
||||
if not response and web_fallback:
|
||||
if ddg.redirect.url:
|
||||
response = ddg.redirect.url
|
||||
|
||||
# final fallback
|
||||
if not response:
|
||||
response = "Sorry, no results."
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1:
|
||||
q = query(" ".join(sys.argv[1:]))
|
||||
keys = q.json.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
sys.stdout.write(key)
|
||||
if type(q.json[key]) in [str, unicode]:
|
||||
print(":", q.json[key])
|
||||
else:
|
||||
sys.stdout.write("\n")
|
||||
for i in q.json[key]:
|
||||
print("\t", i)
|
||||
else:
|
||||
print("Usage: %s [query]" % sys.argv[0])
|
|
@ -0,0 +1,6 @@
|
|||
import random
|
||||
|
||||
evil_file = "/home/krowbar/logs/evildata.txt"
|
||||
|
||||
def get_thing():
|
||||
return "If I Ever Become an Evil Overlord: {}".format(random.choice(list(open(evil_file))).rstrip())
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import json
|
||||
|
||||
names = {
|
||||
"jumblesal": "jumblesale",
|
||||
"hardmath1": "kc",
|
||||
"hardmath123": "kc",
|
||||
"bendorphan": "endorphant",
|
||||
"endorphan": "endorphant",
|
||||
"synergian": "synergiance",
|
||||
}
|
||||
|
||||
def fixName(name):
|
||||
return names[name] if name in names else name
|
||||
|
||||
def get_name(name):
|
||||
names_file = "/home/jumblesale/Code/canonical_names/canonical_names.json"
|
||||
try:
|
||||
with open(names_file) as names_data:
|
||||
names = json.load(names_data)
|
||||
try:
|
||||
return names[name]["userName"]
|
||||
except KeyError:
|
||||
return name
|
||||
except IOError:
|
||||
return name # if we didn't already
|
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/python3
|
||||
import random
|
||||
import re
|
||||
|
||||
dictDir = "/usr/share/dict/"
|
||||
|
||||
def getBanter(morphWord="bant", dictName="words"):
|
||||
with open(dictDir + dictName, "r") as dict:
|
||||
# get rid of all the words with apostrophes
|
||||
words = list(filter(lambda word: re.search(r"^[^']*$", word), dict.readlines()))
|
||||
|
||||
head = getBanterHead(words, morphWord)
|
||||
tail = getBanterTail(words, morphWord)
|
||||
|
||||
if head == "" and tail == "":
|
||||
return "" # dang, we just failed
|
||||
else:
|
||||
# pick randomly between non-empty strings
|
||||
return random.choice([w for w in [head, tail] if w != ""])
|
||||
|
||||
def getBanterHead(words, morphWord):
|
||||
morphHead = morphWord[0:-1]
|
||||
morphLast = morphWord[-1]
|
||||
|
||||
filtered = list(filter(lambda word: re.search(morphHead, word), words))
|
||||
if len(filtered) == 0:
|
||||
return "" # nothing applicable found
|
||||
|
||||
word = random.choice(filtered).strip("\n")
|
||||
end = word.find(morphHead) + len(morphHead)
|
||||
if end == len(word):
|
||||
return word + morphLast
|
||||
else:
|
||||
if "aeiou".find(word[end]) > -1: # just append 't'
|
||||
return word[:end] + morphLast + word[end:]
|
||||
else: # replace the letter with 'b'
|
||||
return word[:end] + morphLast + word[end + 1 :]
|
||||
|
||||
def getBanterTail(words, morphWord):
|
||||
morphTail = morphWord[1:]
|
||||
morphFirst = morphWord[0]
|
||||
|
||||
filtered = list(filter(lambda word: re.search(morphTail, word), words))
|
||||
if len(filtered) == 0:
|
||||
return "" # nothing applicable found
|
||||
|
||||
word = random.choice(filtered).strip("\n")
|
||||
start = word.find(morphTail)
|
||||
if start == 0:
|
||||
return morphFirst + word
|
||||
else:
|
||||
if "aeiou".find(word[start]) > -1: # just append a 'b'
|
||||
return word[:start] + morphFirst + word[start:]
|
||||
else: # replace the letter with 'b'
|
||||
return word[: start - 1] + morphFirst + word[start:]
|
|
@ -0,0 +1,191 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import inflect
|
||||
import random
|
||||
|
||||
p = inflect.engine()
|
||||
LIMIT_GUESSING = True
|
||||
MIN_ROUNDS = 5
|
||||
MAX_ROUNDS = 12
|
||||
SCORE_FILE = "/home/krowbar/Code/irc/data/numberwangscores.txt"
|
||||
SHOW_TOP_NUM = 5
|
||||
GOOD_CHAN = "#bots"
|
||||
|
||||
roundsLeft = 0
|
||||
bonusRound = 0
|
||||
guesses = 0
|
||||
lastGuesser = ""
|
||||
currentScores = {}
|
||||
|
||||
|
||||
def resetGlobals():
|
||||
global roundsLeft
|
||||
global bonusRound
|
||||
global guesses
|
||||
global lastGuesser
|
||||
global currentScores
|
||||
roundsLeft = 0
|
||||
bonusRound = 0
|
||||
guesses = 0
|
||||
lastGuesser = ""
|
||||
currentScores.clear()
|
||||
|
||||
|
||||
# returns a number of lines to be printed out. Numbers represent time to sleep
|
||||
# between prints
|
||||
def start_numberwang(channel, user):
|
||||
if channel != GOOD_CHAN:
|
||||
return [ "Numberwang has been disabled in {} due to spamminess. Please join {} to start a game.".format(channel, GOOD_CHAN) ]
|
||||
|
||||
message = [ "{} started a game".format(user) ]
|
||||
resetGlobals()
|
||||
message.append("It's time for Numberwang!")
|
||||
message.append(1)
|
||||
message.append("Here's how to play:")
|
||||
message.append("1. There are 10 rounds")
|
||||
message.append("2. Each round lasts 10 seconds. You're up against the clock!")
|
||||
message.append("3. Play your numbers, as long as they're between 0 and 99.")
|
||||
message.append("4. That's Numberwang!")
|
||||
message.append(2)
|
||||
message.append("Let's get started!")
|
||||
global roundsLeft
|
||||
global bonusRound
|
||||
roundsLeft = random.randint(MIN_ROUNDS, MAX_ROUNDS)
|
||||
bonusRound = random.randint(2, roundsLeft - 1)
|
||||
# debug print
|
||||
print(
|
||||
"There will be {} rounds with the bonus on round {}".format(
|
||||
str(roundsLeft), str(roundsLeft - bonusRound + 1)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def print_scores():
|
||||
scoreStrs = []
|
||||
first = True
|
||||
for name in currentScores:
|
||||
scoreStrs.append(
|
||||
"{} is {} on {}".format(
|
||||
name,
|
||||
("also " if not first and random.randint(1, 3) == 3 else ""),
|
||||
currentScores[name],
|
||||
)
|
||||
)
|
||||
first = False
|
||||
return p.join(scoreStrs)
|
||||
|
||||
|
||||
def guess_numberwang(user, messageText):
|
||||
global guesses
|
||||
global lastGuesser
|
||||
global currentScores
|
||||
global roundsLeft
|
||||
# print(user + " guessed '" + messageText + "'")
|
||||
guess = re.sub(
|
||||
"[^0-9]", "", messageText.split()[0]
|
||||
) # must have a number in the first 'word'
|
||||
messages = []
|
||||
if guess:
|
||||
if LIMIT_GUESSING and user == lastGuesser:
|
||||
messages.appen("{}, you just guessed! Give another player a try!".format(user))
|
||||
else:
|
||||
guesses += 1
|
||||
lastGuesser = user
|
||||
###CORRECT GUESS###
|
||||
if (
|
||||
random.randint(0, 10) > 10 - guesses
|
||||
): # the more guesses, the higher the probability
|
||||
guesses = 0
|
||||
lastGuesser = ""
|
||||
message = "{}: THAT'S NUMBERWANG!".format(user)
|
||||
points = random.randint(2, 10) * (
|
||||
random.randint(2, 4) if roundsLeft == bonusRound else 1
|
||||
)
|
||||
if user in currentScores.keys():
|
||||
currentScores[user] += points
|
||||
else:
|
||||
currentScores[user] = points
|
||||
roundsLeft -= 1
|
||||
message.append(2)
|
||||
if roundsLeft == 0:
|
||||
messages.append("Numberwang is now over. Thank you for playing!")
|
||||
messages.append("Final scores:")
|
||||
messages.extend(print_scores())
|
||||
save_scores()
|
||||
else:
|
||||
messages.extend(print_scores())
|
||||
newRoundStr = ""
|
||||
if roundsLeft == 1:
|
||||
newRoundStr += "The last round is Wangernumb!"
|
||||
elif roundsLeft == bonusRound:
|
||||
newRoundStr += "**Bonus Round!**"
|
||||
else:
|
||||
newRoundStr += "New Round!"
|
||||
if random.randint(1, 10) > 8:
|
||||
newRoundStr += " Let's rotate the board!"
|
||||
messages.append("{} Start guessing!".format(newRoundStr))
|
||||
|
||||
###INCORRECT GUESS###
|
||||
else:
|
||||
messages.append("{}, {}, {} Numberwang!".format(
|
||||
random.choice(["Sorry", "I'm sorry", "No", "Nope"]),
|
||||
user,
|
||||
random.choice(
|
||||
[
|
||||
"that's not",
|
||||
"that is not",
|
||||
"that isn't",
|
||||
"that is not",
|
||||
"that won't make",
|
||||
"that will not make",
|
||||
]
|
||||
),
|
||||
))
|
||||
|
||||
return messages
|
||||
|
||||
|
||||
def stop_numberwang(user):
|
||||
# print(user + " stopped a game")
|
||||
resetGlobals()
|
||||
return ["Numberwang has been stopped. No points have been awarded. {} is such a party pooper!".format(user)]
|
||||
|
||||
|
||||
def save_scores():
|
||||
with open(SCORE_FILE, "r+") as scorefile:
|
||||
scores = scorefile.readlines()
|
||||
scorefile.seek(0)
|
||||
scorefile.truncate()
|
||||
for line in scores:
|
||||
for name in currentScores:
|
||||
score = line.strip("\n").split("&^%")
|
||||
if score[0] == name:
|
||||
line = "{}&^%{}\n".format(
|
||||
score[0], int(score[1]) + currentScores[name]
|
||||
)
|
||||
del currentScores[name]
|
||||
break
|
||||
scorefile.write(line)
|
||||
|
||||
for name in currentScores: # new wangers
|
||||
scorefile.write("{}&^%{}\n".format(name, currentScores[name]))
|
||||
|
||||
|
||||
def show_highscores():
|
||||
with open(SCORE_FILE, "r") as scorefile:
|
||||
scores = []
|
||||
for line in scorefile.readlines():
|
||||
sline = line.strip("\n").split("&^%")
|
||||
scores.append((int(sline[1]), sline[0]))
|
||||
scores = sorted(scores, reverse=True)[:SHOW_TOP_NUM]
|
||||
|
||||
return ["====TOP WANGERS===="] + [" :== ~{} ({} points!) ==".format(score[1], score[0]) for score in scores]
|
||||
|
||||
def show_user_score(user):
|
||||
with open(SCORE_FILE, "r") as scorefile:
|
||||
for line in scorefile.readlines():
|
||||
score = line.strip("\n").split("&^%")
|
||||
if user == score[0]:
|
||||
return ["{}: Your global numberwang score is {}!".format(user, score[1])]
|
||||
# if we don't find a score line
|
||||
return ["{}: You haven't scored any points yet!".format(user)]
|
|
@ -0,0 +1,187 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import random
|
||||
import hashlib
|
||||
import inflect
|
||||
|
||||
import util.quote_puzzle
|
||||
import util.dict_puzzle
|
||||
import util.textcaptcha
|
||||
|
||||
p = inflect.engine()
|
||||
primes = [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]
|
||||
fuzz_amount = 3
|
||||
|
||||
|
||||
def make_puzzle(obfuscate=True, roll=None):
|
||||
answer = 0
|
||||
bonus = 0
|
||||
puzzle = random.choice(
|
||||
[
|
||||
"Prove you're not a robot: ",
|
||||
"Are you a robot?: ",
|
||||
"Anti-bot check: ",
|
||||
"Counter-cnd0rphant measures: ",
|
||||
"Cosn0k countermeasures: ",
|
||||
"Anti-tilde7hief precautions: ",
|
||||
"Pro-l0gin challenge: ",
|
||||
"Riddle me this: ",
|
||||
"Would you like to play a game? ",
|
||||
"How about this? "
|
||||
]
|
||||
)
|
||||
puzzle += random.choice(
|
||||
[
|
||||
"What is",
|
||||
"What do you get from",
|
||||
"What do you get with",
|
||||
"What is the value of",
|
||||
"Can you answer",
|
||||
"Can you tell me",
|
||||
"Ask wiz3bot what is",
|
||||
"Does anybody know",
|
||||
"Who knows",
|
||||
"Guess what",
|
||||
"Calculate",
|
||||
"Find out"
|
||||
]
|
||||
)
|
||||
puzzle += " "
|
||||
roll = roll or random.randrange(0, 21)
|
||||
var1 = random.randrange(1, 10)
|
||||
var2 = random.randrange(1, 10)
|
||||
var3 = random.randrange(1, 20)
|
||||
var4 = random.randrange(1, 20)
|
||||
let1_ord = random.randrange(ord("a"), ord("z") + 1)
|
||||
|
||||
if roll == 0:
|
||||
answer = var1 + var2
|
||||
puzzle += "{} {} {}".format(
|
||||
p.number_to_words(var1),
|
||||
random.choice(["and", "plus", "sum", "add"]),
|
||||
p.number_to_words(var2),
|
||||
)
|
||||
|
||||
elif roll == 1:
|
||||
answer = var1 * var2
|
||||
puzzle += "{} {} {}".format(
|
||||
p.number_to_words(var1),
|
||||
random.choice(["times", "multiply", "multiplied by", "product"]),
|
||||
p.number_to_words(var2),
|
||||
)
|
||||
|
||||
elif roll == 2:
|
||||
if var2 > var1:
|
||||
var1, var2 = var2, var1
|
||||
answer = var1 - var2
|
||||
puzzle += "{} {} {}".format(
|
||||
p.number_to_words(var1),
|
||||
random.choice(["minus", "subtract", "take away", "less"]),
|
||||
p.number_to_words(var2),
|
||||
)
|
||||
|
||||
elif roll == 3:
|
||||
if var2 > var1:
|
||||
var1, var2 = var2, var1
|
||||
answer = var1 * 2 / var2
|
||||
puzzle += "{} {} {} (no remainder)".format(
|
||||
p.number_to_words(var1 * 2),
|
||||
random.choice(["divided by", "over"]),
|
||||
p.number_to_words(var2),
|
||||
)
|
||||
|
||||
elif roll == 4:
|
||||
answer = var1 ** var2
|
||||
puzzle += "{} to the {} power".format(
|
||||
p.number_to_words(var1), p.ordinal(p.number_to_words(var2))
|
||||
)
|
||||
|
||||
elif roll == 5:
|
||||
p1 = random.choice(primes)
|
||||
p2 = random.choice(primes)
|
||||
|
||||
def answer(guess):
|
||||
# Check the the numbers entered are correct, regardless of order
|
||||
# or surrounding whitespace.
|
||||
attempt = sorted(word.strip() for word in guess.split(","))
|
||||
correct = sorted([str(p1), str(p2)])
|
||||
return attempt == correct
|
||||
|
||||
bonus = 1
|
||||
puzzle += "{} when factored into its two primes (answer in the form of the two primes with a comma between)".format(
|
||||
p.number_to_words(p1 * p2)
|
||||
)
|
||||
|
||||
elif roll == 6:
|
||||
prime = random.choice(primes)
|
||||
answer = prime % var1
|
||||
puzzle += p.number_to_words(prime) + " modulus " + p.number_to_words(var1)
|
||||
elif roll == 7:
|
||||
if let1_ord + var1 > ord("z"):
|
||||
let1_ord -= var1
|
||||
answer = chr(let1_ord + var1)
|
||||
puzzle += "letter comes {} letters after '{}'".format(
|
||||
p.number_to_words(var1), chr(let1_ord)
|
||||
)
|
||||
|
||||
obfuscate = False
|
||||
elif roll == 8:
|
||||
if let1_ord - var1 < ord("a"):
|
||||
let1_ord += var1
|
||||
answer = chr(let1_ord - var1)
|
||||
puzzle += "letter comes {} letters before '{}'".format(
|
||||
p.number_to_words(var1), chr(let1_ord)
|
||||
)
|
||||
|
||||
obfuscate = False
|
||||
elif roll == 9:
|
||||
answer, puzzle = util.quote_puzzle.get_quote()
|
||||
obfuscate = False
|
||||
elif roll == 10:
|
||||
answer = str(min(var1, var2, var3, var4))
|
||||
puzzle += "the {} of {}, {}, {}, and {}".format(
|
||||
random.choice(["smallest", "lowest"]),
|
||||
p.number_to_words(var1),
|
||||
p.number_to_words(var2),
|
||||
p.number_to_words(var3),
|
||||
p.number_to_words(var4),
|
||||
)
|
||||
|
||||
elif roll == 11:
|
||||
answer = str(max(var1, var2, var3, var4))
|
||||
puzzle += "the {} of {}, {}, {}, and {}".format(
|
||||
random.choice(["biggest", "largest"]),
|
||||
p.number_to_words(var1),
|
||||
p.number_to_words(var2),
|
||||
p.number_to_words(var3),
|
||||
p.number_to_words(var4),
|
||||
)
|
||||
|
||||
elif roll <= 14: # 12-14
|
||||
answer, puzzle = util.dict_puzzle.get_puzzle()
|
||||
obfuscate = False
|
||||
elif roll <= 17: # 15-17
|
||||
answer, puzzle = util.dict_puzzle.get_anagram()
|
||||
obfuscate = False
|
||||
elif roll == 18:
|
||||
answer, puzzle = util.quote_puzzle.get_chuck()
|
||||
obfuscate = False
|
||||
elif roll <= 20: #19-20
|
||||
captcha = util.textcaptcha.get_captcha()
|
||||
puzzle = captcha['q'] # the question part of the captcha
|
||||
# print(captcha)
|
||||
answer = lambda a : hashlib.md5(a.encode()).hexdigest() in captcha['a'] # check if the answer is correct
|
||||
obfuscate = False
|
||||
bonus = 1
|
||||
|
||||
# Add a question mark on the end of the question
|
||||
if puzzle[-1] != "?":
|
||||
puzzle += "?"
|
||||
|
||||
if obfuscate == True:
|
||||
for _ in range(fuzz_amount):
|
||||
idx = random.randrange(len(puzzle) - 2) # get between 0 and string length (except the ? mark)
|
||||
puzzle = "".join(
|
||||
[puzzle[0:idx], chr(random.randint(33, 126)), puzzle[idx + 1 :]]
|
||||
)
|
||||
return [puzzle, answer, bonus]
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import json
|
||||
import requests
|
||||
import random
|
||||
import re
|
||||
|
||||
quotefile = "/home/karlen/irc/quotes.txt"
|
||||
chuckfile = "/home/krowbar/Code/irc/data/chuck.txt"
|
||||
chuckApi = "https://api.icndb.com/jokes/random"
|
||||
|
||||
def get_quote():
|
||||
quotes = open(quotefile, "r").read().split("---")
|
||||
quote, attr = random.choice(quotes).strip().splitlines()
|
||||
quote = quote[:200] # get only the first 200 chars
|
||||
word = random.choice([q for q in quote.split(" ") if len(q) > 1])
|
||||
quote = quote.replace(word, re.sub(r"[a-zA-Z]", "_", word))
|
||||
return [word, 'Fill in the blank: "' + quote + '" ' + attr]
|
||||
|
||||
def get_chuck():
|
||||
#chucks = open(chuckfile, "r").readlines()
|
||||
#chuck = random.choice(chucks).rstrip()[:200] # get only the first 200 chars
|
||||
# ha ha! let's see if we can confus login
|
||||
chuck = json.loads(requests.get(chuckApi).content.decode())['value']['joke'][:200]
|
||||
word = random.choice([w for w in chuck.split(" ") if len(w) > 1 and w.lower() != "chuck" and w.lower() != "norris"])
|
||||
chuck = chuck.replace(word, re.sub(r"[a-zA-Z]", "_", word)).replace(""", "\"")
|
||||
return [word, 'Fill in the blank: "{}"'.format(chuck)]
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/python3
|
||||
import requests
|
||||
|
||||
# from lxml.html import fromstring
|
||||
from bs4 import BeautifulSoup
|
||||
import random
|
||||
|
||||
|
||||
def getRhymes(word):
|
||||
words = []
|
||||
url = "http://www.rhymer.com/RhymingDictionaryLast/%s.html" % word
|
||||
soup = BeautifulSoup(requests.get(url).content, "html.parser")
|
||||
|
||||
for t in soup.find_all("table", "table"):
|
||||
words.append(
|
||||
random.choice(
|
||||
[
|
||||
w
|
||||
for w in t.text.split("\n")
|
||||
if w not in [u"", u"\xa0"] and "-" not in w
|
||||
]
|
||||
)
|
||||
)
|
||||
return words
|
||||
|
||||
|
||||
def rhymeZone(word):
|
||||
words = []
|
||||
url = (
|
||||
"http://rhymezone.com/r/rhyme.cgi?Word=%s&typeofrhyme=perfect&org1=syl&org2=l&org3=y"
|
||||
% word
|
||||
)
|
||||
soup = BeautifulSoup(requests.get(url).content, "html.parser")
|
||||
|
||||
for t in soup.find_all("a", "d"):
|
||||
w = t.text.rstrip()
|
||||
if w not in [u"", u"\xa0"] and "?" not in t:
|
||||
words.append(w)
|
||||
random.shuffle(words)
|
||||
return words[0:5]
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import requests
|
||||
|
||||
url = "http://api.textcaptcha.com/krowbar@tilde.town.json"
|
||||
|
||||
def get_captcha():
|
||||
return json.loads(requests.get(url).content.decode())
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
# Import some necessary libraries.
|
||||
import random
|
||||
import inflect
|
||||
import util.puzzle
|
||||
|
||||
p = inflect.engine()
|
||||
challenges = {}
|
||||
SCORE_FILE = "/home/krowbar/Code/irc/data/tildescores.txt"
|
||||
JACKPOT_FILE = "/home/krowbar/Code/irc/data/tildejackpot.txt"
|
||||
JACKPOT_MIN = 3
|
||||
DEBUG = False
|
||||
GOOD_CHAN = "#bots" # The name of the "good" channel that the bot is allowed to run in
|
||||
|
||||
def too_recent(time1, time2):
|
||||
return int(float(time1)) - int(float(time2)) < 60 * 60
|
||||
|
||||
|
||||
def get_positive():
|
||||
return random.choice(
|
||||
[
|
||||
"Yes",
|
||||
"Yep",
|
||||
"Yeppers",
|
||||
"Correct",
|
||||
"You got it",
|
||||
"Yeah",
|
||||
"Right on",
|
||||
"Uh-huh",
|
||||
"Positive",
|
||||
"Totally right",
|
||||
"Close enough",
|
||||
"That's it",
|
||||
"Winner, winner",
|
||||
"Bingo",
|
||||
"Affirmative",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_negative():
|
||||
return random.choice(
|
||||
[
|
||||
"No",
|
||||
"Nope",
|
||||
"Sorry",
|
||||
"Wrong",
|
||||
"Nuh-uh",
|
||||
"Negatory",
|
||||
"Incorrect",
|
||||
"Not today",
|
||||
"Try again",
|
||||
"Maybe later",
|
||||
"Maybe next time",
|
||||
"Probably not",
|
||||
"Answer hazy",
|
||||
"Not quite",
|
||||
"Not even close",
|
||||
"Not for you",
|
||||
"I think not"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_superlative(score):
|
||||
if score > 4:
|
||||
return random.choice(
|
||||
[
|
||||
"super cool",
|
||||
"totally rad",
|
||||
"extraordinary",
|
||||
"dynomite",
|
||||
"#topdrawer",
|
||||
"a #TopLad",
|
||||
"the cat's meow",
|
||||
"a tilde town hero",
|
||||
"my favorite person",
|
||||
"incredibly lucky",
|
||||
"unbelievable",
|
||||
"a tilde town hunk",
|
||||
"could bring all the boys to the yard",
|
||||
"worth twice their weight in gold",
|
||||
"the hero we need",
|
||||
"no ordinary townie",
|
||||
]
|
||||
)
|
||||
elif score > 2:
|
||||
return random.choice(
|
||||
[
|
||||
"really cool",
|
||||
"pretty neat",
|
||||
"rather nice",
|
||||
"a dynamic doggo",
|
||||
"radical",
|
||||
"intense",
|
||||
"pretty lucky",
|
||||
"knows the territory",
|
||||
"has what it takes",
|
||||
"has mad skillz",
|
||||
"going the distance",
|
||||
"a hard worker",
|
||||
"my sunshine",
|
||||
"ready to rumble",
|
||||
]
|
||||
)
|
||||
else:
|
||||
return random.choice(
|
||||
[
|
||||
"cool",
|
||||
"nice",
|
||||
"acceptible",
|
||||
"good enough",
|
||||
"a promising pupper",
|
||||
"better than a horse",
|
||||
"swell",
|
||||
"a little lucky",
|
||||
"just credible",
|
||||
"my friend",
|
||||
"probably not a robot",
|
||||
"valuable to the team",
|
||||
"now trending",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_bad_thing():
|
||||
return random.choice(
|
||||
[
|
||||
"is a meanie",
|
||||
"mugs me right off",
|
||||
"miffed me off",
|
||||
"is worse than a horse",
|
||||
"smells like a ghost",
|
||||
"probably didn't bathe today",
|
||||
"probably shakes babies",
|
||||
"didn't guess hard enough",
|
||||
"isn't lucky",
|
||||
"smells of elderberries",
|
||||
"should reconsider their life choices",
|
||||
"did't believe in the heart of the tilde",
|
||||
"came to the wrong side of town",
|
||||
"should have stopped while they were ahead",
|
||||
"requires annotations from an authoratative source",
|
||||
"could have been a contender",
|
||||
"spreads vicious rumors",
|
||||
"drank my milkshake",
|
||||
"is probably cheating",
|
||||
"is trying too hard",
|
||||
"didn't really try",
|
||||
"should try harder",
|
||||
"caught me in a bad mood",
|
||||
"should have gone with their first choice",
|
||||
"did not receive IFR clearance from tower",
|
||||
"was tardy for class",
|
||||
"is on double secret probation",
|
||||
"forgot their keys",
|
||||
"forgot to bribe me",
|
||||
"forgot to close the door",
|
||||
"waited too long",
|
||||
"doesn't call me on my cellphone",
|
||||
"isn't wearing a seatbelt",
|
||||
"didn't courtesy flush",
|
||||
"asked a bot for answers",
|
||||
"was right but I didn't feel like it",
|
||||
"is right on opposite day",
|
||||
"actually answered the last question",
|
||||
"has their pants on backwards",
|
||||
"forgot their own name",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def get_prize(user, isHuman, bonus=0):
|
||||
prizes = [1] * 8 + [2] * 4 + [3] * 2 + [5] * isHuman # no 5pt prize for non-humans
|
||||
prize = random.choice(prizes) + bonus
|
||||
if (
|
||||
random.randint(1, 10) > 6 - 4 * isHuman
|
||||
): # 80% of the time it's a normal prize (40% for not humans)
|
||||
return [
|
||||
prize,
|
||||
"{}: {}! You are {} and get {} tildes!".format(
|
||||
user,
|
||||
(get_positive() if isHuman else get_negative()),
|
||||
get_superlative(prize),
|
||||
p.number_to_words(prize),
|
||||
),
|
||||
]
|
||||
else: # 20% of the time its a jackpot situation
|
||||
with open(JACKPOT_FILE, "r+") as jackpotfile:
|
||||
jackpot = int(jackpotfile.readline().strip("\n"))
|
||||
jackpotfile.seek(0)
|
||||
jackpotfile.truncate()
|
||||
if (
|
||||
random.randint(1, 10) > 1 or not isHuman
|
||||
): # 90% of the time it's a non-prize. non-humans never win jackpot
|
||||
new_jackpot = jackpot + max(1, prize)
|
||||
jackpotfile.write(
|
||||
str(new_jackpot)
|
||||
) # increase the jackpot by the prize size
|
||||
return [
|
||||
0,
|
||||
"{} {} and gets no tildes! (Jackpot is now {} tildes)".format(
|
||||
user, get_bad_thing(), new_jackpot
|
||||
),
|
||||
]
|
||||
else: # hit jackpot!
|
||||
jackpotfile.write(str(JACKPOT_MIN))
|
||||
return [
|
||||
jackpot,
|
||||
"{} hit the jackpot and won **{}** tildes!".format(
|
||||
user, p.number_to_words(jackpot)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def show_jackpot():
|
||||
with open(JACKPOT_FILE, "r") as jackpotfile:
|
||||
jackpot = int(jackpotfile.readline().strip("\n"))
|
||||
return "The jackpot is currently {} tildes!".format(p.number_to_words(jackpot))
|
||||
|
||||
|
||||
def give_tilde(user, time, human, bonus=0):
|
||||
found = False
|
||||
with open(SCORE_FILE, "r+") as scorefile:
|
||||
scores = scorefile.readlines()
|
||||
scorefile.seek(0)
|
||||
scorefile.truncate()
|
||||
message = ""
|
||||
for score in scores:
|
||||
name, score_on_file, timestamp = score.strip("\n").split("&^%")
|
||||
if name == user:
|
||||
found = True
|
||||
if too_recent(time, timestamp) and not DEBUG:
|
||||
message = "{} asked for a tilde too recently and {}. Try again later.".format(user, get_bad_thing())
|
||||
else:
|
||||
prizevalue, prizetext = get_prize(user, human, bonus)
|
||||
score = "{}&^%{}&^%{}\n".format(
|
||||
user, str(int(score_on_file) + prizevalue), time
|
||||
)
|
||||
message = prizetext
|
||||
scorefile.write(score)
|
||||
if not found:
|
||||
prizevalue, prizetext = get_prize(user, True, bonus)
|
||||
scorefile.write("{}&^%{}&^%{}\n".format(user, str(prizevalue + 1), time))
|
||||
message = "Welcome to the tilde game, {}! Here's {} free tildes to start you off.".format(user, p.number_to_words(prizevalue + 1))
|
||||
|
||||
return message
|
||||
|
||||
|
||||
def show_tildescore(user):
|
||||
with open(SCORE_FILE, "r") as scorefile:
|
||||
for _idx, score in enumerate(scorefile):
|
||||
record = score.strip("\n").split("&^%")
|
||||
if record[0] == user:
|
||||
return "{} has {} tildes!".format(user, p.number_to_words(record[1]))
|
||||
# person has not played yet
|
||||
return "{} has no tildes yet!".format(user)
|
||||
|
||||
|
||||
def challenge(channel, user, time):
|
||||
global challenges
|
||||
challenge = util.puzzle.make_puzzle()
|
||||
challenges[user] = challenge[1:]
|
||||
return "{}: {}".format(user, challenge[0])
|
||||
|
||||
|
||||
def challenge_response(user, time, msg):
|
||||
global challenges
|
||||
# print(msg)
|
||||
response = ""
|
||||
if user in challenges:
|
||||
answer, bonus = challenges[user]
|
||||
if (callable(answer) and answer(msg.lower())) or (
|
||||
msg.lower() == str(answer).lower() or msg == p.number_to_words(answer)
|
||||
):
|
||||
response = give_tilde(user, time, True, bonus)
|
||||
else:
|
||||
response = give_tilde(user, time, False, 0)
|
||||
del challenges[user]
|
||||
# delete the user from challenges either way
|
||||
return response
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import inflect
|
||||
import random
|
||||
|
||||
scores_file = "/home/krowbar/Code/irc/data/topicscores.txt"
|
||||
channel_topics = "/home/krowbar/Code/irc/data/topics_{}.txt"
|
||||
random_topics = "/home/krowbar/Code/irc/data/randomtopics.txt"
|
||||
|
||||
p = inflect.engine()
|
||||
|
||||
def get_topic(channel, user, time):
|
||||
# topic scores are saved as <USER>&^%<GETS SCORE>&^%<SETS SCORE>
|
||||
with open(scores_file, "r") as scorefile:
|
||||
scores = scorefile.readlines()
|
||||
userscore = 1
|
||||
found = False
|
||||
with open(scores_file, "w") as scorefile:
|
||||
for idx, score in enumerate(scores):
|
||||
data = score.strip("\n").split("&^%")
|
||||
if data[0] == user:
|
||||
found = True
|
||||
userscore = int(data[1]) + 1
|
||||
scores[idx] = data[0] + "&^%" + str(userscore) + "&^%" + data[2] + "\n"
|
||||
scorefile.writelines(scores)
|
||||
if not found:
|
||||
scorefile.write(user + "&^%1&^%0\n")
|
||||
|
||||
with open(channel_topics.format(channel), "r") as topics:
|
||||
topic = topics.readlines()[-1].strip("\n").split("&^%", 3)
|
||||
byuser = util.get_name(topic[1])
|
||||
return "I've told you {} times! It's \"{}\" (set by {} {})".format(
|
||||
p.number_to_words(userscore),
|
||||
topic[2],
|
||||
byuser,
|
||||
util.pretty_date(int(topic[0])),
|
||||
)
|
||||
|
||||
|
||||
def count_topic(channel, user, time, msg):
|
||||
with open(channel_topic.format(channel), "a") as topics:
|
||||
topics.write(time + "&^%" + user + "&^%" + msg + "\n")
|
||||
with open(scores_file, "r") as scorefile:
|
||||
scores = scorefile.readlines()
|
||||
userscore = 1
|
||||
found = False
|
||||
with open(scores_file, "w") as scorefile:
|
||||
for idx, score in enumerate(scores):
|
||||
data = score.strip("\n").split("&^%")
|
||||
if data[0] == user:
|
||||
found = True
|
||||
userscore = int(data[2]) + 1
|
||||
scores[idx] = data[0] + "&^%" + data[1] + "&^%" + str(userscore) + "\n"
|
||||
scorefile.writelines(scores)
|
||||
if not found:
|
||||
scorefile.write(user + "&^%0&^%1")
|
||||
return "{} has changed the topic {} times!".format(user, p.number_to_words(userscore))
|
||||
|
||||
|
||||
def set_topic(channel, user, time, msg):
|
||||
ircsock.send("TOPIC " + channel + " :" + msg + "\n")
|
||||
return count_topic(channel, user, time, msg)
|
||||
|
||||
|
||||
def random_topic(channel, user, time, setTopic=False):
|
||||
with open(random_topics) as rtopics:
|
||||
msg = random.choice(rtopics.readlines()).strip("\n")
|
||||
if setTopic:
|
||||
set_topic(channel, user, time, msg)
|
||||
else:
|
||||
return "Suggested Topic: {}".format(msg)
|
||||
|
||||
|
||||
def rollcall(channel):
|
||||
return "topicbot reporting! I respond to !topic !settopic !suggesttopic !thistory"
|
||||
|
||||
|
||||
def topic_history(channel, user, count):
|
||||
try:
|
||||
iCount = int(count.split()[1])
|
||||
except (ValueError, IndexError):
|
||||
iCount = 3
|
||||
if iCount > 10:
|
||||
iCount = 10
|
||||
if iCount < 1:
|
||||
iCount = 3
|
||||
|
||||
with open(channel_topics.format(channel), "r") as topicsfile:
|
||||
message = "Ok, here are the last {} topics".format(p.number_to_words(iCount))
|
||||
for idx, topic in enumerate(reversed(topicsfile.readlines()[-iCount:])):
|
||||
topic = topic.strip("\n").split("&^%", 3)
|
||||
byuser = util.get_name(topic[1])
|
||||
message += "\n{}: {} (set by {} {})".format( str(idx + 1), topic[2], byuser, util.pretty_date(int(topic[0])) )
|
||||
|
||||
return message
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/python3
|
||||
from bs4 import BeautifulSoup
|
||||
import random
|
||||
import re
|
||||
import requests
|
||||
|
||||
def tumble(url):
|
||||
# Find the max pages
|
||||
soup = BeautifulSoup(requests.get(url).content, "html.parser")
|
||||
pages = soup.findAll("span", "page-numbers")[0].text.split("/")[
|
||||
1
|
||||
] # this could totally fail several ways
|
||||
tries = 3
|
||||
while True:
|
||||
try:
|
||||
page = random.randrange(1, int(pages) + 1)
|
||||
|
||||
# Parse a page
|
||||
soup = BeautifulSoup(
|
||||
requests.get("{}/page/{}".format(url, page)).content, "html.parser"
|
||||
)
|
||||
article = random.choice(soup.findAll("article"))
|
||||
quote = article.find("blockquote").text.replace("\n", "")
|
||||
if len(article.find("footer").findAll("ul")) > 1:
|
||||
quote += re.sub(
|
||||
"\n+", " ", article.find("footer").findAll("ul")[0].text
|
||||
)
|
||||
# the hash tags
|
||||
quote += (
|
||||
"("
|
||||
+ re.sub("\n+", " ", article.find("footer").findAll("ul")[1].text)
|
||||
+ ")"
|
||||
)
|
||||
# and the date and notes
|
||||
else:
|
||||
quote += (
|
||||
"("
|
||||
+ re.sub("\n+", " ", article.find("footer").findAll("ul")[0].text)
|
||||
+ ")"
|
||||
)
|
||||
# just the date and notes
|
||||
|
||||
return quote
|
||||
except: # sometimes we fail. let's retry a few times
|
||||
if tries == 0:
|
||||
return ""
|
||||
else:
|
||||
tries -= 1
|
||||
break
|
|
@ -0,0 +1,10 @@
|
|||
import random
|
||||
|
||||
|
||||
def get_thing():
|
||||
file = "/home/krowbar/logs/welchdata.txt"
|
||||
thing = ""
|
||||
return (
|
||||
"Thing Mr. Welch can no longer do in a RPG #"
|
||||
+ random.choice(list(open(file))).rstrip()
|
||||
)
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import datetime
|
||||
import fileinput
|
||||
import time
|
||||
import calendar
|
||||
import re
|
||||
import operator
|
||||
from util import nameFix
|
||||
|
||||
MAX_NODES = 5
|
||||
|
||||
logfile = "/home/archangelic/irc/log"
|
||||
timeCutoff = calendar.timegm(time.gmtime()) - (3 * 7 * 24 * 60 * 60) # 3 weeks
|
||||
|
||||
def whoSaid(text):
|
||||
if not text:
|
||||
return "No text given :("
|
||||
else:
|
||||
result = whoSaid_data(text)
|
||||
date = datetime.date.fromtimestamp(result["timecutoff"])
|
||||
dateStr = date.strftime("%B %d")
|
||||
if not result["data"]:
|
||||
msg = "Nobody said '%s' since %s" % (text, dateStr)
|
||||
else:
|
||||
msg = "Since %s, %s said '%s' %d times" % (
|
||||
dateStr,
|
||||
result["data"][0][0],
|
||||
text,
|
||||
result["data"][0][1],
|
||||
)
|
||||
if len(result["data"]) > 1:
|
||||
msg += " and %s said it %d times" % (
|
||||
result["data"][1][0],
|
||||
result["data"][1][1],
|
||||
)
|
||||
return msg
|
||||
|
||||
def whoSaid_data(word):
|
||||
word = word.lower()
|
||||
userData = (
|
||||
{}
|
||||
) # hash keyed by "user" that contains a hash of mentioned other users with count
|
||||
# Get a list of all user names by checking the logs for people who have said things
|
||||
with open(logfile, "r") as log:
|
||||
for line in log:
|
||||
try:
|
||||
time, user, message = line.split("\t", 3)
|
||||
time = int(time)
|
||||
user = nameFix.fixName(user).lower()
|
||||
except ValueError:
|
||||
continue # There are some bad lines in the log file that we'll ignore if we can't parse
|
||||
|
||||
if time > timeCutoff and message[0] is not "!" and word in message.lower():
|
||||
if user in userData:
|
||||
userData[user] += 1
|
||||
else:
|
||||
userData[user] = 1
|
||||
userData = sorted(userData.items(), key=operator.itemgetter(1), reverse=True)
|
||||
return {"timecutoff": timeCutoff, "data": userData}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/python3
|
||||
from bs4 import BeautifulSoup
|
||||
import random
|
||||
import requests
|
||||
|
||||
|
||||
def get_philosophy(word, max_steps=20):
|
||||
step_words = [word]
|
||||
steps = 0
|
||||
|
||||
url = "https://en.wikipedia.org/wiki/%s" % word
|
||||
while steps < max_steps:
|
||||
print("url: {}".format(url))
|
||||
soup = BeautifulSoup(requests.get(url).content, "html.parser")
|
||||
title = soup.find("h1", id="firstHeading")
|
||||
content = soup.find("div", id="mw-content-text")
|
||||
if not content:
|
||||
break
|
||||
item = [
|
||||
item
|
||||
for item in content.find_all("a")
|
||||
if not item.get("class")
|
||||
and not item.get("target")
|
||||
and item.get("title")
|
||||
and not "Wikipedia:" in item.get("title")
|
||||
and not "Category:" in item.get("title")
|
||||
and not "Help:" in item.get("title")
|
||||
and not "Portal:" in item.get("title")
|
||||
and not "Special:" in item.get("title")
|
||||
and not "Talk:" in item.get("title")
|
||||
and not "Template:" in item.get("title")
|
||||
and not "File:" in item.get("title")
|
||||
and "Edit section:" not in item.get("title")
|
||||
and "Commons:" not in item.get("title")
|
||||
and not item.get("title") in step_words
|
||||
][0]
|
||||
step_words.append(item.get("title"))
|
||||
# print item.get('title') + "\n"
|
||||
url = "https://en.wikipedia.org{}".format(item.get("href"))
|
||||
steps += 1
|
||||
return step_words
|
||||
|
||||
|
||||
def containsAny(str, set):
|
||||
return 1 in [c in str for c in set]
|
||||
|
||||
|
||||
def get_philosophy_lower(word, max_steps=20):
|
||||
step_words = [word]
|
||||
steps = 0
|
||||
|
||||
url = "https://en.wikipedia.org/wiki/{}".format(word.replace(" ", "%20"))
|
||||
while steps < max_steps:
|
||||
print("url: {}".format(url))
|
||||
soup = BeautifulSoup(requests.get(url).content, "html.parser")
|
||||
|
||||
if soup.find(id="noarticletext"):
|
||||
step_words.append("(not found)")
|
||||
break
|
||||
|
||||
title = soup.find("h1", id="firstHeading")
|
||||
content = soup.find("div", id="mw-content-text")
|
||||
if not content:
|
||||
break
|
||||
links = [
|
||||
item
|
||||
for item in content.find_all("a")
|
||||
if not item.get("class")
|
||||
and item.text
|
||||
and item.text[0].islower()
|
||||
and not containsAny(item.text, ":()")
|
||||
and item.get("title")
|
||||
and not containsAny(item.get("title"), ":()")
|
||||
and not item.get("title") in step_words
|
||||
]
|
||||
if not links:
|
||||
step_words.append("(dead end)")
|
||||
break
|
||||
item = links[0] # grab the first good link item
|
||||
# print "Checking %s %s" % (item.get('title'), item.text)
|
||||
step_words.append(item.get("title"))
|
||||
if item.get("title") == "Philosophy":
|
||||
break
|
||||
# print item.get('title') + "\n"
|
||||
url = "https://en.wikipedia.org%s" % item.get("href")
|
||||
steps += 1
|
||||
return step_words
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/python3
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import util.duckduckgo
|
||||
|
||||
def xkcd(query):
|
||||
res = util.duckduckgo.get_zci("site:xkcd.com " + query)
|
||||
title = ""
|
||||
try: # ddg returns a url for these searches. i want a title as well
|
||||
title = BeautifulSoup(requests.get(res).content, "html.parser").title.text
|
||||
except:
|
||||
pass # just swallow the error. maybe the result wasn't a url or something else bad happened
|
||||
return [(((title + " - ") if title else "") + res)]
|
||||
|
||||
|
||||
# never mind, blocked by ddg
|
||||
# def xkcd_links(query):
|
||||
# url = "https://duckduckgo.com/html/?q=site%3Axkcd.com+" + query.replace(' ', '+')
|
||||
# soup = BeautifulSoup(requests.get(url).content, 'html.parser')
|
||||
# items = soup.find_all("a", class_="result__a")
|
||||
# print items
|
||||
# items = list(filter(lambda i: i[0:8] == 'xkcd.com',
|
||||
# [i.find(class_="result__title").text.strip() for i in items]))
|
||||
# print items
|
||||
# def pretty_link(item):
|
||||
# url = item.find(class_="result__url").text.strip()
|
||||
# title = item.find(class_="result__title").text.strip()
|
||||
# return (title + ' - ' + url) if title else url
|
||||
#
|
||||
# links = map(lambda url: pretty_link(url), items)
|
||||
# return links
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import pinhook.plugin
|
||||
import time
|
||||
from util import numberwang
|
||||
|
||||
@pinhook.plugin.register('!rollcall')
|
||||
def rollcall_plugin(msg):
|
||||
return pinhook.plugin.message("Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers")
|
||||
|
||||
# the numberwang lib returns message lists that may contain numbers.
|
||||
# if we get one of those, sleep for that long
|
||||
def print_messages(msg, messages):
|
||||
for line in messages:
|
||||
if isinstance(line, int) or isinstance(line, float):
|
||||
time.sleep(line)
|
||||
else:
|
||||
msg.privmsg(msg.channel, line)
|
||||
|
||||
@pinhook.plugin.register('!numberwang')
|
||||
def numberwang_plugin(msg):
|
||||
if numberwang.roundsLeft == 0:
|
||||
print_messages(msg, numberwang.start_numberwang(msg.channel, msg.nick))
|
||||
|
||||
@pinhook.plugin.register('!wangernumb')
|
||||
def wangernumb_plugin(msg):
|
||||
if numberwang.roundsLeft > 0:
|
||||
print_messages(msg, numberwang.stop_numberwang(msg.nick))
|
||||
|
||||
@pinhook.plugin.register('!topwangers')
|
||||
def top_plugin(msg):
|
||||
print_messages(msg, numberwang.show_highscores())
|
||||
|
||||
@pinhook.plugin.register('!myscore')
|
||||
def my_score_plugin(msg):
|
||||
print_messages(msg, numberwang.show_user_score(msg.nick))
|
||||
|
||||
@pinhook.plugin.listener('numberwang')
|
||||
def numberwang_listener(msg):
|
||||
if msg.text.split()[0] in ['!numberwang', '!wangernumb', '!topwangers', '!myscore'] or numberwang.roundsLeft is 0 or msg.channel != numberwang.GOOD_CHAN:
|
||||
return
|
||||
|
||||
print_messages(msg, numberwang.guess_numberwang(msg.channel, msg.user, msg.arg))
|
|
@ -0,0 +1,13 @@
|
|||
It was the bottom of the {{an ordinal number, ending in -th or -rd}} and the {{a city}} {{an animal, plural}} were down {{a number}} points against their rivals, the {{a city}} {{an occupation}}.
|
||||
Young {{a male name}} Jackson was up to the plate. He'd have to {{a verb}} this pitch if his team any chance of winning the game.
|
||||
The pitch came in {{an adjective}}, the batter swung but was too {{another adjective}}! Strike one!
|
||||
The second pitch, but {{a noun}} got in the batter's {{a body part}}! Strike two!
|
||||
"{{an encouraging aphorism}}" somebody shouted from the stands.
|
||||
The pitcher wound up and threw a {{a shape}}. The batter hit the ball but it went wide! "{{an adjective}} ball!" The umpire yelled.
|
||||
The batter was feeling very {{an emotion}}, {{a liquid}} was pouring down his face.
|
||||
"You'll never be able to hit this one!" the pitcher {{a verb, past tense}} before letting loose!
|
||||
The batter closed his eyes, wished on his lucky {{an astrological body, plural}}, and swung.
|
||||
"{{a loud sound effect}}!"
|
||||
The ball flew over the {{a direction}} field wall! Home run!
|
||||
After he ran the bases, his teammates cheered and slapped him on the {{a body part}}!
|
||||
The game was tied up, but it still wasn't over... (To be continued?)
|
|
@ -0,0 +1,3 @@
|
|||
Here is a number {{a number#}} ordinal {{a number#|ordinal}}, numeric {{a number#|numeric}}
|
||||
Here is a word {{a word#1}} upper {{a word#1|upper}} lower {{a word#1|lower}}
|
||||
Here is another word {{a word#2}} title {{a word#2|title}}
|
Loading…
Reference in New Issue