]> gitweb.pimeys.fr Git - bots/hung.git/blobdiff - hung.py
Plantait si on lui proposait un mot en dehors d'une partie
[bots/hung.git] / hung.py
diff --git a/hung.py b/hung.py
index 0691b364cb245dbff411ada7304443497dc53c88..c96f834e5b994f84afb4364babf221ded7a42ad9 100755 (executable)
--- a/hung.py
+++ b/hung.py
@@ -29,15 +29,39 @@ config_play_channels=["#flood"]
 config_quiet_channels=[]
 config_logfile_template="hung.%s.log"
 def get_config_logfile(serveur):
-    serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
+    serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans","localhost":"localhost"}
     return config_logfile_template%(serveurs[serveur])
-config_overops=["[20-100]","[20-100]_"]
+config_overops=["[20-100]","[20-100]_","Petite-Peste","PEB"]
 config_ops=[]
 config_report_bugs_to=["[20-100]"]
 
 config_dico_mots="mots.txt"
 config_dico_defs="definitions.txt"
 
+config_scores_file="scores.pickle"
+
+config_tag_triggers=[u"t(|a)g",u"ta gueule",u"la ferme",u"ferme( |-)la",u"tais-toi",u"chut"]
+config_tag_actions=[u"se tait",u"ferme sa gueule",u"se la ferme",u"la ferme"]
+config_tag_answers=[u"J'me tais si j'veux !",
+u"Je t'entends pas :°",
+u"Héhé, try again",
+u"Non, j'ai pas envie",
+u"Peut-être quand toi tu la fermeras, et encore…"]
+
+config_quit_messages=[u"_ _ _, _ _ _ _ _   _ _ _ _ _!",
+u"_ _ E, _ _ _ E _   _ _ _ _ _!",
+u"_ _ E, _ _ _ E _   _ O _ _ _!",
+u"_ _ E, _ _ U E _   _ O _ _ _!",
+u"_ _ E, _ R U E _   _ O R _ _!",
+u"_ _ E, _ R U E L   _ O R L _!",
+u"B _ E, _ R U E L   _ O R L _!",
+u"B _ E, C R U E L   _ O R L _!",
+u"B _ E, C R U E L   _ O R L D!",
+u"B Y E, C R U E L   _ O R L D!",
+u"B Y E, C R U E L   W O R L D!",
+]
+config_leave_messages=["On finira la partie plus tard :p"]
+
 def log(serveur,channel,auteur=None,message=None):
     f=open(get_config_logfile(serveur),"a")
     if auteur==message==None:
@@ -50,6 +74,7 @@ def log(serveur,channel,auteur=None,message=None):
         print chain
     f.close()
 
+
 class UnicodeBotError(Exception):
     pass
 def bot_unicode(chain):
@@ -58,11 +83,37 @@ def bot_unicode(chain):
     except UnicodeDecodeError as exc:
         raise UnicodeBotError
 
+def remplace_accents(chaine):
+    chaine=chaine.lower()
+    remplacements = {u"á":u"a",u"à":u"a",u"â":u"a",u"ä":u"a",u"é":u"e",u"è":u"e",u"ê":u"e",u"ë":u"e",u"í":u"i",u"ì":u"i",u"î":u"i",u"ï":u"i",u"ó":u"o",   u"ò":u"o",u"ô":u"o",u"ö":u"o",u"ú":u"u",u"ù":u"u",u"û":u"u",u"ü":u"u",u"ý":u"y",u"ỳ":u"y",u"ŷ":u"y",u"ÿ":u"y",u"œ":u"oe",u"æ":u"ae"}
+    for avant,apres in remplacements.items():
+        chaine=chaine.replace(avant,apres)
+    return chaine
+
+def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
+    if case_sensitive:
+        chain=unicode(chain,"utf8")
+    else:
+        chain=unicode(chain,"utf8").lower()
+    allmatches="("+"|".join(matches)+")"
+    reg=(avant+allmatches+apres).lower()
+    o=re.match(reg,chain)
+    return o
+
+def is_tag(chain):
+    return is_something(chain,config_tag_triggers)
+
+def is_mot(mot,liste):
+    real_word = "".join([lettre[0] for lettre in liste])
+    real_word = real_word.decode("utf8").lower()
+    mot=remplace_accents(mot.decode("utf8"))
+    return mot==real_word
+
 class Hung(ircbot.SingleServerIRCBot):
     def __init__(self,serveur,debug=False):
         temporary_pseudo=config_irc_pseudo+str(random.randrange(10000,100000))
         ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
-                              temporary_pseudo,"Bot irc pour embêter Shadobot", 10)
+                              temporary_pseudo,"Bot irc pour jouer au pendu", 10)
         self.debug=debug
         self.serveur=serveur
         self.overops=config_overops
@@ -71,7 +122,7 @@ class Hung(ircbot.SingleServerIRCBot):
         self.chanlist=config_chanlist
         self.stay_channels=config_stay_channels
         self.play_channels=config_play_channels
-        self.play_status={}
+        self.play_status={i:[None,None,None] for i in self.play_channels}
         self.quiet_channels=config_quiet_channels
 
 
@@ -82,6 +133,7 @@ class Hung(ircbot.SingleServerIRCBot):
         serv.nick(config_irc_pseudo)
     
     def on_welcome(self, serv, ev):
+        self.serv=serv # ça serv ira :)
         self.give_me_my_pseudo(serv)
         serv.privmsg("NickServ","IDENTIFY %s"%(config_irc_password))
         log(self.serveur,"Connected")
@@ -131,7 +183,7 @@ class Hung(ircbot.SingleServerIRCBot):
             if auteur in self.ops and len(message)>1:
                 if message[1] in self.chanlist:
                     if not (message[1] in self.stay_channels) or auteur in self.overops:
-                        serv.part(message[1])
+                        self.quitter(message[1]," ".join(message[2:]))
                         self.chanlist.remove(message[1])
                         log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                     else:
@@ -149,7 +201,7 @@ class Hung(ircbot.SingleServerIRCBot):
                         log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
                     else:
                         self.play_channels.append(message[1])
-                        self.play_status[message[1]]=[[None,None]]
+                        self.play_status[message[1]]=[None,None,None]
                         serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
                         log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                 else:
@@ -198,12 +250,15 @@ class Hung(ircbot.SingleServerIRCBot):
         elif cmd in ["states","status"]:
             if auteur in self.overops:
                 for k in self.play_status.keys():
-                    serv.privmsg(auteur,"%s : %s (%s)"%(k,"".join([str(i[0]) for i in self.play_status[k][0]])
-                                                     ,self.play_status[k][1]))
+                    if self.play_status[k]==[None,None,None]:
+                        serv.privmsg(auteur,"None")
+                    else:
+                        serv.privmsg(auteur,"%s : %s (%s) [%s]"%(k,"".join([str(i[0]) for i in self.play_status[k][0]])
+                                                     ,self.play_status[k][1], self.play_status[k][2]))
         elif cmd=="die":
             if auteur in self.overops:
                 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
-                self.die()
+                self.mourir()
             else:
                 notunderstood=True
         elif cmd=="quiet":
@@ -248,6 +303,8 @@ class Hung(ircbot.SingleServerIRCBot):
                 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
             else:
                 notunderstood=True
+        elif cmd in ["score","scores"]:
+            self.send_scores(serv,auteur)
         else:
             notunderstood=True
         if notunderstood:
@@ -265,8 +322,8 @@ class Hung(ircbot.SingleServerIRCBot):
         indice = random.randrange(0,len(mots))
         mot,definition=mots[indice],defs[indice]
         # ' et - sont considérés comme déjà devinés
-        mot = [(lettre,lettre in "'-") for lettre in list(mot)]
-        self.play_status[canal]=[mot,definition]
+        mot = [(lettre,lettre in "'-()") for lettre in list(mot)]
+        self.play_status[canal]=[mot,definition,{}]
         self.affiche_mot(serv, canal, begin="Devinez")
 
     def on_pubmsg(self, serv, ev):
@@ -279,7 +336,7 @@ class Hung(ircbot.SingleServerIRCBot):
             if not canal in self.quiet_channels:
                 serv.privmsg(canal,
                   "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
-                return
+            return
         pour_moi,message=self.pourmoi(serv,message)
         if pour_moi and message.split()!=[]:
             cmd=message.split()[0].lower()
@@ -290,14 +347,14 @@ class Hung(ircbot.SingleServerIRCBot):
             if cmd in ["meurs","die","crève"]:
                 if auteur in self.overops:
                     log(self.serveur,canal,auteur,message+"[successful]")
-                    self.die()
+                    self.mourir()
                 else:
                     serv.privmsg(canal,"%s: crève !"%(auteur))
                     log(self.serveur,canal,auteur,message+"[failed]")
             elif cmd in ["part","leave","dégage"]:
                 if auteur in self.ops and (not (canal in self.stay_channels)
                                            or auteur in self.overops):
-                    serv.part(canal,message="Éjecté par %s"%(auteur))
+                    self.quitter(canal)
                     log(self.serveur,canal,auteur,message+"[successful]")
                     if canal in self.chanlist:
                         self.chanlist.remove(canal)
@@ -307,36 +364,61 @@ class Hung(ircbot.SingleServerIRCBot):
             elif cmd in ["play","jeu","encore","again","partie","pendu","game","mot","go","allez"]:
                 if not canal in self.quiet_channels and canal in self.play_channels:
                     if self.play_status.has_key(canal):
-                        if self.play_status[canal]==[[None,None]]:
+                        if self.play_status[canal]==[None,None,None]:
                             self.start_partie(serv, canal)
                         else:
                             self.affiche_mot(serv, canal, begin="%s: Rappel"%(auteur))
                     else:
-                        self.play_status[canal]=[[None,None]]
+                        self.play_status[canal]=[None,None,None]
                         self.start_partie(serv, canal)
                 elif not canal in self.play_channels:
                     serv.privmsg(canal,"%s: pas ici…"%(auteur))
             elif (cmd in list("azertyuiopqsdfghjklmwxcvbn") and canal in self.play_channels 
-                  and self.play_status.has_key(canal) and self.play_status[canal]!=[[None,None]]):
+                  and self.play_status.has_key(canal) and self.play_status[canal]!=[None,None,None]):
                 giv_let=cmd.upper()
                 liste=self.play_status[canal][0]
                 listeapres=[(lettre[0],lettre[1] or lettre[0]==giv_let) for lettre in liste]
                 if liste!=listeapres:
+                    nbtrouvees=(sum([lettre[1] for lettre in listeapres if not lettre[0] in "'-()"])
+                                - sum([lettre[1] for lettre in liste if not lettre[0] in "'-()"]))
+                    if self.play_status[canal][2].has_key(auteur):
+                        self.play_status[canal][2][auteur]+= nbtrouvees
+                    else:
+                        self.play_status[canal][2][auteur] = nbtrouvees
                     self.play_status[canal][0]=listeapres
                     self.affiche_mot(serv, canal, begin="%s placé"%(giv_let))
                 if all([lettre[1] for lettre in listeapres]):
-                    realword="".join([lettre[0] for lettre in self.play_status[canal][0]])
-                    definition = self.play_status[canal][1]
-                    serv.privmsg(canal,"Bravo ! C'était %s"%(realword))
-                    serv.privmsg(canal,definition)
-                    self.play_status[canal]=[[None,None]]
+                    self.gagne(serv, canal)
                     
-                
+            elif cmd in ["score","scores","!score","!scores"]:
+                self.send_scores(serv,auteur)
             if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
                 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
+            if is_tag(message) and not canal in self.quiet_channels:
+                if auteur in self.ops:
+                    action=random.choice(config_tag_actions)
+                    serv.action(canal,action.encode("utf8"))
+                    self.quiet_channels.append(canal)
+                else:
+                    answer=random.choice(config_tag_answers)
+                    for ligne in answer.split("\n"):
+                        serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
+            # on essaye de voir si le mot fourni matche la partie en cours
+            mot = cmd
+            if self.play_status[canal][0]!=None and is_mot(mot, self.play_status[canal][0]):
+                # on a trouvé le mot
+                # on regarde combien de lettre il manquait
+                manquait = sum([not lettre[1] for lettre in self.play_status[canal][0]])
+                self.add_score({auteur: manquait})
+                if self.play_status[canal][2].has_key(auteur):
+                    self.play_status[canal][2][auteur]+=manquait
+                else:
+                    self.play_status[canal][2][auteur]=manquait
+                self.gagne(serv, canal, bonus=auteur, bonusvalue=manquait)
         else:
             pass
 
+
     def on_action(self, serv, ev):
         action = ev.arguments()[0]
         auteur = irclib.nm_to_n(ev.source())
@@ -348,7 +430,55 @@ class Hung(ircbot.SingleServerIRCBot):
               "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
             return
         mypseudo=serv.get_nickname()
-        
+    
+    def quitter(self,chan,leave_message=None):
+        if leave_message==None:
+            leave_message=random.choice(config_leave_messages)
+        self.serv.part(chan,message=leave_message.encode("utf8"))
+    
+    def mourir(self):
+        quit_message=random.choice(config_quit_messages)
+        self.die(msg=quit_message.encode("utf8"))
+    
+    def get_scores(self):
+        f=open(config_scores_file)
+        scores=pickle.load(f)
+        f.close()
+        return scores
+    def save_scores(self,scores):
+        f=open(config_scores_file,'w')
+        pickle.dump(scores,f)
+        f.close()
+    def add_score(self,dico):
+        scores=self.get_scores()
+        for k,v in dico.items():
+            if scores.has_key(k):
+                scores[k]+=v
+            else:
+                scores[k]=v
+        self.save_scores(scores)
+    def send_scores(self, serv, destinataire):
+        scores=self.get_scores()
+        scores=scores.items()
+        scores.sort(lambda x,y:cmp(x[1],y[1]))
+        scores.reverse()
+        serv.privmsg(destinataire,"Scores by score : "+" ; ".join(["%s %s"%(k,v) for (k,v) in scores]) )
+        scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
+        serv.privmsg(destinataire,"Scores by pseudo : "+" ; ".join(["%s %s"%(k,v) for (k,v) in scores]) )
+
+    def gagne(self, serv, canal, bonus=None, bonusvalue=2):
+        realword="".join([lettre[0] for lettre in self.play_status[canal][0]])
+        definition = self.play_status[canal][1]
+        serv.privmsg(canal,"Bravo ! C'était %s"%(realword))
+        serv.privmsg(canal,definition)
+        nlettre=float(len(realword.replace("'","").replace("-","")))
+        contribs=["%s:%s%%%s"%(pseudo,str(int(100*contrib/nlettre)),("+bonus(%s)"%(bonusvalue))*(bonus==pseudo)) for pseudo,contrib in self.play_status[canal][2].items()]
+        contribs_score={pseudo:int(10*contrib/nlettre) for pseudo,contrib in self.play_status[canal][2].items()}
+        self.add_score(contribs_score)
+        serv.privmsg(canal,"Contributions : %s"%("  ".join(contribs)) )
+        self.play_status[canal]=[None,None,None]
+
+
 if __name__=="__main__":
     import sys
     if len(sys.argv)==1:
@@ -360,7 +490,8 @@ if __name__=="__main__":
     else:
         debug=False
     serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
-              "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
+              "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org",
+              "localhost":"localhost"}
     try:
         serveur=serveurs[serveur]
     except KeyError: