Browse Source

added a tokenbucket algo rate limiter, and added the detective role

master
jcao219 14 years ago
parent
commit
ef9f3b0093
  1. 40
      oyoyo/client.py
  2. 29
      var.py
  3. 4
      wolfbot.py
  4. 56
      wolfgame.py

40
oyoyo/client.py

@ -17,12 +17,49 @@
import logging import logging
import socket import socket
import time
from oyoyo.parse import parse_raw_irc_command from oyoyo.parse import parse_raw_irc_command
class IRCClientError(Exception): class IRCClientError(Exception):
pass pass
# Adapted from http://code.activestate.com/recipes/511490-implementation-of-the-token-bucket-algorithm/
class TokenBucket(object):
"""An implementation of the token bucket algorithm.
>>> bucket = TokenBucket(80, 0.5)
>>> bucket.consume(1)
"""
def __init__(self, tokens, fill_rate):
"""tokens is the total tokens in the bucket. fill_rate is the
rate in tokens/second that the bucket will be refilled."""
self.capacity = float(tokens)
self._tokens = float(tokens)
self.fill_rate = float(fill_rate)
self.timestamp = time.time()
def consume(self, tokens):
"""Consume tokens from the bucket. Returns True if there were
sufficient tokens otherwise False."""
if tokens <= self.tokens:
self._tokens -= tokens
else:
return False
return True
@property
def tokens(self):
if self._tokens < self.capacity:
now = time.time()
delta = self.fill_rate * (now - self.timestamp)
self._tokens = min(self.capacity, self._tokens + delta)
self.timestamp = now
return self._tokens
def add_commands(d): def add_commands(d):
def dec(cls): def dec(cls):
for c in d: for c in d:
@ -70,6 +107,7 @@ class IRCClient(object):
self.port = None self.port = None
self.connect_cb = None self.connect_cb = None
self.blocking = True self.blocking = True
self.tokenbucket = TokenBucket(3, 7.3)
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
self.command_handler = cmd_handler self.command_handler = cmd_handler
@ -181,6 +219,8 @@ class IRCClient(object):
self.socket.close() self.socket.close()
def msg(self, user, msg): def msg(self, user, msg):
for line in msg.split('\n'): for line in msg.split('\n'):
while not self.tokenbucket.consume(1):
time.sleep(1)
self.send("PRIVMSG", user, ":{0}".format(line)) self.send("PRIVMSG", user, ":{0}".format(line))
privmsg = msg # Same thing privmsg = msg # Same thing
def notice(self, user, msg): def notice(self, user, msg):

29
var.py

@ -18,18 +18,19 @@ MANSLAUGHTER_CHANCE = 1/5
GAME_MODES = {} GAME_MODES = {}
###################################################################################################### #################################################################################################################
# ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL ## # ROLE INDEX: PLAYERS SEER WOLF CURSED DRUNK HARLOT TRAITOR GUNNER CROW ANGEL DETECTIVE ##
###################################################################################################### #################################################################################################################
ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0), ## ROLES_GUIDE = { 4 : ( 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
6 : ( 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0), ## 6 : ( 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 ), ##
8 : ( 1 , 2 , 1 , 1 , 1 , 0 , 0 , 0 , 0), ## 8 : ( 1 , 2 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 ), ##
10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0), ## 10 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 ), ##
11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1), ## 11 : ( 1 , 2 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 ), ##
None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0)} ## 15 : ( 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 ), ##
###################################################################################################### None : ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )} ##
#################################################################################################################
# Notes: ## # Notes: ##
###################################################################################################### #################################################################################################################
ROLE_INDICES = {0 : "seer", ROLE_INDICES = {0 : "seer",
@ -40,7 +41,8 @@ ROLE_INDICES = {0 : "seer",
5 : "traitor", 5 : "traitor",
6 : "gunner", 6 : "gunner",
7 : "werecrow", 7 : "werecrow",
8 : "guardian angel"} 8 : "guardian angel",
9 : "detective"}
INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items()) INDEX_OF_ROLE = dict((v,k) for k,v in ROLE_INDICES.items())
@ -98,7 +100,8 @@ CHANGEABLE_ROLES = { "seers" : INDEX_OF_ROLE["seer"],
"traitors" : INDEX_OF_ROLE["traitor"], "traitors" : INDEX_OF_ROLE["traitor"],
"gunners" : INDEX_OF_ROLE["gunner"], "gunners" : INDEX_OF_ROLE["gunner"],
"werecrows" : INDEX_OF_ROLE["werecrow"], "werecrows" : INDEX_OF_ROLE["werecrow"],
"angels" : INDEX_OF_ROLE["guardian angel"]} "angels" : INDEX_OF_ROLE["guardian angel"],
"detectives" : INDEX_OF_ROLE["detective"]}

4
wolfbot.py

@ -39,7 +39,11 @@ def main():
nickname=botconfig.NICK, nickname=botconfig.NICK,
connect_cb=wolfgame.connect_callback connect_cb=wolfgame.connect_callback
) )
try:
cli.mainLoop() cli.mainLoop()
except Exception as e:
cli.msg(botconfig.CHANNEL, "An error has occured: "+str(e))
raise e
if __name__ == "__main__": if __name__ == "__main__":

56
wolfgame.py

@ -183,7 +183,7 @@ def take_op(cli, nick, chan, rest):
@cmd("!sudo revoke", owner_only=True) @cmd("!sudo revoke", owner_only=True)
def revoke(cli, nick, chan, rest): def revoke(cli, nick, chan, rest):
r = rest.strip() r = rest.strip()
if r in botconfig.ADMINS: if var.CLOAKS[var.USERS.index(r)] in botconfig.ADMINS:
ladmins = list(botconfig.ADMINS) ladmins = list(botconfig.ADMINS)
ladmins.remove(r) ladmins.remove(r)
botconfig.ADMINS = tuple(ladmins) botconfig.ADMINS = tuple(ladmins)
@ -729,6 +729,9 @@ def on_nick(cli, prefix, nick):
if prefix in var.WOUNDED: if prefix in var.WOUNDED:
var.WOUNDED.remove(prefix) var.WOUNDED.remove(prefix)
var.WOUNDED.append(nick) var.WOUNDED.append(nick)
if prefix in var.INVESTIGATED:
var.INVESTIGATED.remove(prefix)
var.INVESTIGATED.append(prefix)
if prefix in var.VOTES: if prefix in var.VOTES:
var.VOTES[nick] = var.VOTES.pop(prefix) var.VOTES[nick] = var.VOTES.pop(prefix)
for v in var.VOTES.values(): for v in var.VOTES.values():
@ -816,6 +819,7 @@ def transition_day(cli, gameid=0):
# Reset daytime variables # Reset daytime variables
var.VOTES = {} var.VOTES = {}
var.INVESTIGATED = []
var.WOUNDED = [] var.WOUNDED = []
var.DAY_START_TIME = datetime.now() var.DAY_START_TIME = datetime.now()
@ -1173,6 +1177,45 @@ def observe(cli, nick, rest):
@pmcmd("id", "!id")
def investigate(cli, nick, rest):
if var.PHASE in ("none", "join"):
cli.notice(nick, "No game is currently running.")
return
elif nick not in var.list_players():
cli.notice(nick, "You're not currently playing.")
return
if not var.is_role(nick, "detective"):
cli.msg(nick, "Only a detective may use this command.")
return
if var.PHASE != "day":
cli.msg(nick, "You may only investigate people during the day.")
return
if nick in var.INVESTIGATED:
cli.msg(nick, "You may only investigate one person per round.")
return
victim = re.split("\s+", rest)[0].strip().lower()
if not victim:
cli.msg(nick, "Not enough parameters")
return
pl = var.list_players()
pll = [x.lower() for x in pl]
if victim not in pll:
cli.msg(nick, "\u0002{0}\u0002 is currently not playing.".format(victim))
return
victim = pl[pll.index(victim)]
var.INVESTIGATED.append(nick)
cli.msg(nick, ("The results of your investigation have returned. \u0002{0}\u0002"+
" is a... \u0002{1}\u0002").format(victim, var.get_role(victim)))
if random.random < 0.4: # a 2/5 chance (should be changeable in settings)
# Reveal his role!
for badguy in var.ROLES["wolf"] + var.ROLES["werecrow"] + var.ROLES["traitor"]:
cli.msg(badguy, ("\0002{0}\0002 accidentally drops a paper. The paper reveals "+
"that (s)he is the detective!").format(nick))
@pmcmd("visit", "!visit") @pmcmd("visit", "!visit")
def hvisit(cli, nick, rest): def hvisit(cli, nick, rest):
if var.PHASE in ("none", "join"): if var.PHASE in ("none", "join"):
@ -1330,7 +1373,7 @@ def relay(cli, nick, rest):
return return
badguys = var.ROLES["wolf"] + var.ROLES["traitor"] + var.ROLES["werecrow"] badguys = var.ROLES["wolf"] + var.ROLES["traitor"] + var.ROLES["werecrow"]
if len(badguys) > 1: if len(badguys) > 1:
if var.get_role(nick) in ("wolf","traitor","werecrow"): if nick in badguys:
badguys.remove(nick) # remove self from list badguys.remove(nick) # remove self from list
for badguy in badguys: for badguy in badguys:
cli.msg(badguy, "{0} says: {1}".format(nick, rest)) cli.msg(badguy, "{0} says: {1}".format(nick, rest))
@ -1425,7 +1468,11 @@ def transition_night(cli):
' wolf, there is a 50/50 chance of you dying, if you guard '+ ' wolf, there is a 50/50 chance of you dying, if you guard '+
'a victim, they will live. Use !guard to guard a player.')); 'a victim, they will live. Use !guard to guard a player.'));
cli.msg(g_angel, "Players: " + ", ".join(pl)) cli.msg(g_angel, "Players: " + ", ".join(pl))
for dttv in var.ROLES["detective"]:
cli.msg(dttv, ("You are a \u0002detective\u0002.\n"+
"It is your job to determine all the wolves and traitors. "+
"Your job is during the day, and you can see the true "+
"identity of all users, even traitors."))
for d in var.ROLES["village drunk"]: for d in var.ROLES["village drunk"]:
cli.msg(d, 'You have been drinking too much! You are the \u0002village drunk\u0002.') cli.msg(d, 'You have been drinking too much! You are the \u0002village drunk\u0002.')
@ -1698,7 +1745,6 @@ def fwait(cli, nick, chan, rest):
"{1} seconds.").format(nick, var.EXTRA_WAIT)) "{1} seconds.").format(nick, var.EXTRA_WAIT))
@cmd("!reset") @cmd("!reset",admin_only=True)
def reset_game(cli, nick, chan, rest): def reset_game(cli, nick, chan, rest):
if nick in ("nyuszika7h", "jcao219"):
reset(cli) reset(cli)
Loading…
Cancel
Save