2015-01-22 20:09:04 +00:00
#!/usr/bin/python
# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python
# Import some necessary libraries.
import socket
import os
import sys
from optparse import OptionParser
import fileinput
import random
import time
import re
import operator
import formatter
import get_users
import mentions
import pretty_date
import inflect
parser = OptionParser ()
2018-10-05 16:02:38 -04:00
parser . add_option (
"-s" ,
"--server" ,
dest = "server" ,
default = "127.0.0.1" ,
help = "the server to connect to" ,
metavar = "SERVER" ,
)
parser . add_option (
"-c" ,
"--channel" ,
dest = "channel" ,
default = "#bot_test" ,
help = "the channel to join" ,
metavar = "CHANNEL" ,
)
parser . add_option (
"-n" ,
"--nick" ,
dest = "nick" ,
default = "numberwang_bot" ,
help = "the nick to use" ,
metavar = "NICK" ,
)
2015-01-22 20:09:04 +00:00
( options , args ) = parser . parse_args ()
p = inflect . engine ()
2016-01-06 14:08:25 -05:00
LIMIT_GUESSING = True
2015-01-23 17:42:11 +00:00
MIN_ROUNDS = 5
MAX_ROUNDS = 12
2015-01-22 20:09:04 +00:00
SCORE_FILE = "numberwangscores.txt"
SHOW_TOP_NUM = 5
2015-01-29 21:05:37 +00:00
GOOD_CHAN = "#bots"
2015-01-22 20:09:04 +00:00
roundsLeft = 0
bonusRound = 0
guesses = 0
lastGuesser = ""
currentScores = {}
2018-10-05 16:02:38 -04:00
2015-01-22 20:09:04 +00:00
def resetGlobals ():
2018-10-05 16:02:38 -04:00
global roundsLeft
global bonusRound
global guesses
global lastGuesser
global currentScores
roundsLeft = 0
bonusRound = 0
guesses = 0
lastGuesser = ""
currentScores . clear ()
2015-01-22 20:09:04 +00:00
2018-10-05 13:56:15 -04:00
def ping ( pong ):
2018-10-05 16:02:38 -04:00
ircsock . send ( "PONG {} \n " . format ( pong ))
def sendmsg ( chan , msg ):
ircsock . send ( "PRIVMSG " + chan + " :" + msg + " \n " )
2015-01-22 20:09:04 +00:00
def joinchan ( chan ):
2018-10-05 16:02:38 -04:00
ircsock . send ( "JOIN " + chan + " \n " )
2015-01-22 20:09:04 +00:00
def hello ():
2018-10-05 16:02:38 -04:00
ircsock . send ( "PRIVMSG " + channel + " :Hello! \n " )
2015-01-22 20:09:04 +00:00
def start_numberwang ( channel , user ):
2018-10-05 16:02:38 -04:00
if channel != "#bots" :
ircsock . send (
"PRIVMSG "
+ channel
+ " :Numberwang has been disabled for "
+ channel
+ " due to spamminess. Please join "
+ GOOD_CHAN
+ " to start a game. \n "
)
2015-01-29 21:05:37 +00:00
return
2018-10-05 16:02:38 -04:00
print ( user + " started a game" )
2015-01-22 20:09:04 +00:00
resetGlobals ()
ircsock . send ( "PRIVMSG " + channel + " :It's time for Numberwang! \n " )
time . sleep ( 1 )
ircsock . send ( "PRIVMSG " + channel + " :Here's how to play: \n " )
ircsock . send ( "PRIVMSG " + channel + " :1. There are 10 rounds \n " )
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG "
+ channel
+ " :2. Each round lasts 10 seconds. You're up against the clock! \n "
)
ircsock . send (
"PRIVMSG "
+ channel
+ " :3. Play your numbers, as long as they're between 0 and 99. \n "
)
2015-01-22 20:09:04 +00:00
ircsock . send ( "PRIVMSG " + channel + " :4. That's Numberwang! \n " )
time . sleep ( 2 )
ircsock . send ( "PRIVMSG " + channel + " :Let's get started! \n " )
global roundsLeft
global bonusRound
2018-10-05 16:02:38 -04:00
roundsLeft = random . randint ( MIN_ROUNDS , MAX_ROUNDS )
bonusRound = random . randint ( 2 , roundsLeft - 1 )
print (
"There will be "
+ str ( roundsLeft )
+ " rounds with the bonus on round "
+ str ( roundsLeft - bonusRound + 1 )
)
2015-01-22 20:09:04 +00:00
def print_scores ( channel ):
scoreStrs = []
first = True
for name in currentScores :
2018-10-05 16:02:38 -04:00
scoreStrs . append (
name
+ " is "
+ ( "also " if not first and random . randint ( 1 , 3 ) == 3 else "" )
+ "on "
+ str ( currentScores [ name ])
)
2015-01-22 20:09:04 +00:00
first = False
ircsock . send ( "PRIVMSG " + channel + " :" + p . join ( scoreStrs ) + "! \n " )
2018-10-05 16:02:38 -04:00
2015-01-22 20:09:04 +00:00
def guess_numberwang ( channel , user , messageText ):
global guesses
global lastGuesser
global currentScores
global roundsLeft
2018-10-05 16:02:38 -04:00
print ( user + " guessed '" + messageText + "'" )
guess = re . sub (
"[^0-9]" , "" , messageText . split ()[ 0 ]
) # must have a number in the first 'word'
if guess :
if LIMIT_GUESSING and user == lastGuesser :
ircsock . send (
"PRIVMSG "
+ channel
+ " :"
+ user
+ ", you just guessed! Give another player a try! \n "
)
2015-01-22 20:09:04 +00:00
else :
guesses += 1
lastGuesser = user
###CORRECT GUESS###
2018-10-05 16:02:38 -04:00
if (
random . randint ( 0 , 10 ) > 10 - guesses
): # the more guesses, the higher the probability
2015-01-22 20:09:04 +00:00
guesses = 0
lastGuesser = ""
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG " + channel + " :" + user + ": THAT'S NUMBERWANG! \n "
)
points = random . randint ( 2 , 10 ) * (
random . randint ( 2 , 4 ) if roundsLeft == bonusRound else 1
)
2015-01-22 20:09:04 +00:00
if user in currentScores . keys ():
currentScores [ user ] += points
else :
currentScores [ user ] = points
roundsLeft -= 1
time . sleep ( 2 )
2018-10-05 16:02:38 -04:00
if roundsLeft == 0 :
ircsock . send (
"PRIVMSG "
+ channel
+ " :Numberwang is now over. Thank you for playing! \n "
)
2015-01-22 20:09:04 +00:00
ircsock . send ( "PRIVMSG " + channel + " :Final scores: \n " )
print_scores ( channel )
save_scores ()
else :
print_scores ( channel )
newRoundStr = ""
2018-10-05 16:02:38 -04:00
if roundsLeft == 1 :
2015-01-22 20:09:04 +00:00
newRoundStr += "The last round is Wangernumb!"
2018-10-05 16:02:38 -04:00
elif roundsLeft == bonusRound :
2015-01-22 20:09:04 +00:00
newRoundStr += "**Bonus Round!**"
else :
newRoundStr += "New Round!"
2018-10-05 16:02:38 -04:00
if random . randint ( 1 , 10 ) > 8 :
2015-01-22 20:09:04 +00:00
newRoundStr += " Let's rotate the board!"
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG " + channel + " :" + newRoundStr + " Start guessing! \n "
)
2015-01-22 20:09:04 +00:00
###INCORRECT GUESS###
else :
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG "
+ channel
+ " :"
+ 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" ,
]
)
+ " Numberwang! \n "
)
2015-01-22 20:09:04 +00:00
def stop_numberwang ( channel , user ):
2018-10-05 16:02:38 -04:00
print ( user + " stopped a game" )
2015-01-22 20:09:04 +00:00
resetGlobals ()
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG "
+ channel
+ " :Numberwang has been stopped. No points have been awarded. "
+ user
+ " is such a party pooper! \n "
)
2015-01-22 20:09:04 +00:00
def save_scores ():
with open ( SCORE_FILE , "r+" ) as scorefile :
scores = scorefile . readlines ()
scorefile . seek ( 0 )
scorefile . truncate ()
2015-01-23 17:42:11 +00:00
for line in scores :
for name in currentScores :
2015-01-22 20:09:04 +00:00
score = line . strip ( " \n " ) . split ( "&^%" )
2018-10-05 16:02:38 -04:00
if score [ 0 ] == name :
line = (
score [ 0 ]
+ "&^%"
+ str ( int ( score [ 1 ]) + currentScores [ name ])
+ " \n "
)
2015-10-13 08:23:17 -05:00
del currentScores [ name ]
2015-01-23 17:42:11 +00:00
break
scorefile . write ( line )
2018-10-05 16:02:38 -04:00
for name in currentScores : # new wangers
2015-01-23 17:42:11 +00:00
line = name + "&^%" + str ( currentScores [ name ]) + " \n "
scorefile . write ( line )
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
2015-01-22 20:09:04 +00:00
def show_highscores ( channel ):
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 ]
ircsock . send ( "PRIVMSG " + channel + " : ====TOP WANGERS==== \n " )
for score in scores :
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG "
+ channel
+ " :== ~"
+ score [ 1 ]
+ " ("
+ str ( score [ 0 ])
+ " points!) == \n "
)
2015-01-22 20:09:04 +00:00
def show_user_score ( channel , user ):
with open ( SCORE_FILE , "r" ) as scorefile :
for line in scorefile . readlines ():
score = line . strip ( " \n " ) . split ( "&^%" )
2018-10-05 16:02:38 -04:00
if user == score [ 0 ]:
ircsock . send (
"PRIVMSG "
+ channel
+ " :"
+ user
+ ": Your global numberwang score is "
+ str ( score [ 1 ])
+ "! \n "
)
2015-01-22 20:09:04 +00:00
return
2018-10-05 16:02:38 -04:00
# if we don't find a score line
ircsock . send (
"PRIVMSG "
+ channel
+ " :"
+ user
+ ": You haven't scored any points yet! \n "
)
2015-01-22 20:09:04 +00:00
def rollcall ( channel ):
2018-10-05 16:02:38 -04:00
ircsock . send (
"PRIVMSG "
+ channel
+ " :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 \n "
)
2015-01-22 20:09:04 +00:00
def connect ( server , channel , botnick ):
2018-10-05 16:02:38 -04:00
ircsock . connect (( server , 6667 ))
ircsock . send (
"USER " + botnick + " " + botnick + " " + botnick + " :krowbar \n "
) # user authentication
ircsock . send ( "NICK " + botnick + " \n " )
joinchan ( channel )
joinchan ( GOOD_CHAN )
2015-01-22 20:09:04 +00:00
def get_user_from_message ( msg ):
2018-10-05 16:02:38 -04:00
try :
i1 = msg . index ( ":" ) + 1
i2 = msg . index ( "!" )
return msg [ i1 : i2 ]
except ValueError :
return ""
2015-01-22 20:09:04 +00:00
def listen ():
2018-10-05 16:02:38 -04:00
while 1 :
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
ircmsg = ircsock . recv ( 2048 )
ircmsg = ircmsg . strip ( " \n\r " )
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
if ircmsg [: 4 ] == "PING" :
ping ( ircmsg . split ( " " )[ 1 ])
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
formatted = formatter . format_message ( ircmsg )
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
if "" == formatted :
continue
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
# print formatted
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
split = formatted . split ( " \t " )
time = split [ 0 ]
user = split [ 1 ]
command = split [ 2 ]
channel = split [ 3 ]
messageText = split [ 4 ]
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
if ircmsg . find ( ":!numberwang" ) != - 1 and roundsLeft == 0 :
start_numberwang ( channel , user )
2015-01-29 21:05:37 +00:00
2018-10-05 16:02:38 -04:00
if channel == GOOD_CHAN :
if ircmsg . find ( ":!wangernumb" ) != - 1 and roundsLeft > 0 :
stop_numberwang ( channel , user )
if roundsLeft > 0 :
guess_numberwang ( channel , user , messageText )
2015-01-29 21:05:37 +00:00
2018-10-05 16:02:38 -04:00
if ircmsg . find ( ":!topwangers" ) != - 1 :
show_highscores ( channel )
if ircmsg . find ( ":!myscore" ) != - 1 :
show_user_score ( channel , user )
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
if ircmsg . find ( ":!rollcall" ) != - 1 :
rollcall ( channel )
2015-01-22 20:09:04 +00:00
2018-10-05 16:02:38 -04:00
if ircmsg [: 4 ] == "PING" :
ping ( ircmsg . split ( " " )[ 1 ])
sys . stdout . flush ()
time . sleep ( 1 )
2015-01-22 20:09:04 +00:00
ircsock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
connect ( options . server , options . channel , options . nick )
listen ()