Index: XpartaMuPP.py
===================================================================
--- XpartaMuPP.py	(revision 16016)
+++ XpartaMuPP.py	(working copy)
@@ -158,66 +158,117 @@
     return game
  
   def verifyGame(self, gamereport):
+    print("VERIFYING")
     """
       Returns a boolean based on whether the game should be rated.
       Here, we can specify the criteria for rated games.
     """
+    # First check how many people have won. Teams may be balanced but if everyone
+    # allies in the game then don't rate it 
     winning_jids = list(dict.keys({jid: state for jid, state in
                                   gamereport['playerStates'].items()
                                   if state == 'won'}))
-    # We only support 1v1s right now. TODO: Support team games.
     if len(winning_jids) * 2 > len(dict.keys(gamereport['playerStates'])):
       # More than half the people have won. This is not a balanced team game or duel.
+      print(gamereport)
+      print(winning_jids)
       return False
-    if len(dict.keys(gamereport['playerStates'])) != 2:
+
+    # Check that teams are balanced
+    teams = list(dict.values(gamereport['teams']))
+    teamSize = 1
+    for i in range(1, len(dict.keys(gamereport['playerStates']))):
+      if teams[0] == teams[i] and teams[i] != -1:
+        teamSize += 1
+    if teamSize * 2 != len(dict.keys(gamereport['playerStates'])) and len(dict.keys(gamereport['playerStates'])) != 2:
+      print(teamSize)
+      print(teams)
+      print(gamereport)
       return False
+
     return True
 
   def rateGame(self, game):
+    print("RATING")
     """
-      Takes a game with 2 players and alters their ratings
+      Takes a balanced team game and alters their ratings
       based on the result of the game.
       Returns self.
       Side effects:
         Changes the game's players' ratings in the database.
     """
-    player1 = game.players[0]
-    player2 = game.players[1]
     # TODO: Support draws. Since it's impossible to draw in the game currently,
     # the database model, and therefore this code, requires a winner.
     # The Elo implementation does not, however.
-    result = 1 if player1 == game.winner else -1
+    winners = []
+    losers = []
+
+    # First we set the teams to 1 & 2 if it's a 1 v 1. 
+    if len(game.players) == 2:
+      game.player_info[0].teams = 1
+      game.player_info[1].teams = 2
+
+    # Find the first winner in the game
+    for i in range(len(game.players)):
+      if game.players[i] == game.winner:
+        winners.append(i)
+        break
+
+    # The first loop finds 1 of the winners in a team game. The second loop
+    # then find the other winners by looking for the player who is on the
+    # same team as him. Anyone who is not on his/her team is then a loser
+    for i in range(0, (len(game.players))):
+      if i != winners[0]:
+        if game.player_info[winners[0]].teams == game.player_info[i].teams:
+          winners.append(i)
+        else:
+          losers.append(i)
+
     # Player's ratings are -1 unless they have played a rated game.
-    if player1.rating == -1:
-      player1.rating = leaderboard_default_rating
-    if player2.rating == -1:
-      player2.rating = leaderboard_default_rating
+    for i in range(len(game.players)):
+      if game.players[i].rating == -1:
+        game.players[i].rating = leaderboard_default_rating
 
-    rating_adjustment1 = int(get_rating_adjustment(player1.rating, player2.rating,
-      len(player1.games), len(player2.games), result))
-    rating_adjustment2 = int(get_rating_adjustment(player2.rating, player1.rating,
-      len(player2.games), len(player1.games), result * -1))
-    if result == 1:
-      resultQualitative = "won"
-    elif result == 0:
-      resultQualitative = "drew"
-    else:
-      resultQualitative = "lost"
-    name1 = '@'.join(player1.jid.split('@')[:-1])
-    name2 = '@'.join(player2.jid.split('@')[:-1])
-    self.lastRated = "A rated game has ended. %s %s against %s. Rating Adjustment: %s (%s -> %s) and %s (%s -> %s)."%(name1, 
-      resultQualitative, name2, name1, player1.rating, player1.rating + rating_adjustment1,
-      name2, player2.rating, player2.rating + rating_adjustment2)
-    player1.rating += rating_adjustment1
-    player2.rating += rating_adjustment2
-    if not player1.highest_rating:
-      player1.highest_rating = -1
-    if not player2.highest_rating:
-      player2.highest_rating = -1
-    if player1.rating > player1.highest_rating:
-      player1.highest_rating = player1.rating
-    if player2.rating > player2.highest_rating:
-      player2.highest_rating = player2.rating
+    winners_ratings_adjustments = []
+    losers_ratings_adjustments = []
+    winners_ratings = []
+    losers_ratings = []
+    winners_names = []
+    losers_names = []
+
+    # Assemble an list of the players' previous ratings
+    for i in range(len(winners)):
+      winners_ratings.append(game.players[winners[i]].rating)
+      losers_ratings.append(game.players[losers[i]].rating)
+
+    # Calculate ratings
+    for i in range(len(winners)):
+      winners_ratings_adjustments.append(int(get_rating_adjustment(winners_ratings[i], winners_ratings, 
+        losers_ratings, len(game.players[winners[i]].games), 1)))
+      losers_ratings_adjustments.append(int(get_rating_adjustment(losers_ratings[i], losers_ratings, 
+        winners_ratings, len(game.players[losers[i]].games), -1)))
+      # Get the names of each player
+      winners_names.append( '@'.join(game.players[winners[i]].jid.split('@')[:-1]))
+      losers_names.append('@'.join(game.players[losers[i]].jid.split('@')[:-1]))
+
+    # Generate the message for the ratings
+    winnersNameStr = ""
+    winnersRatingStr = ""
+    losersNameStr = ""
+    losersRatingStr = ""
+    winnersNameStr = ", ".join(winners_names[:-1]) + (" and " if len(winners_names) != 1 else "") + winners_names[-1]
+    ratingAdjustmentList = list(map(lambda name, rating, adjustment:"%s (%s -> %s)" %(name, rating, rating + adjustment), winners_names, winners_ratings, winners_ratings_adjustments))
+    winnersRatingStr = ", ".join(ratingAdjustmentList[:-1]) + (" and " if len(ratingAdjustmentList) != 1 else "") + ratingAdjustmentList[-1]
+    losersNameStr = ", ".join(losers_names[:-1]) + (" and " if len(losers_names) != 1 else "") + losers_names[-1]
+    ratingAdjustmentList = list(map(lambda name, rating, adjustment:"%s (%s -> %s)" %(name, rating, rating + adjustment), losers_names, losers_ratings, losers_ratings_adjustments))
+    losersRatingStr = ", ".join(ratingAdjustmentList[:-1]) + (" and " if len(ratingAdjustmentList) != 1 else "") + ratingAdjustmentList[-1]
+    # Construct message
+    self.lastRated = "A rated game has ended. " + winnersNameStr + " won against " + losersNameStr + ". Rating Adjustments: " + winnersRatingStr + " won aginst " + losersRatingStr + "."
+
+    # Change the ratings in the database
+    for i in range(len(winners)):
+      game.players[winners[i]].rating += winners_ratings_adjustments[i]
+      game.players[losers[i]].rating += losers_ratings_adjustments[i]
     db.commit()
     return self
 
@@ -317,6 +368,7 @@
     self.leaderboard = leaderboard
     self.interimReportTracker = []
     self.interimJIDTracker = []
+    self.processedGameReport = {}
 
   def addReport(self, JID, rawGameReport):
     """
@@ -354,10 +406,12 @@
         Python data structures leaving JIDs empty.
       Returns a processed gameReport of type dict.
     """
-    processedGameReport = {}
+
+    inProcessGameReport = {}
+    statToJID = {}
     for key in rawGameReport:
       if rawGameReport[key].find(",") == -1:
-        processedGameReport[key] = rawGameReport[key]
+        inProcessGameReport[key] = rawGameReport[key]
       else:
         split = rawGameReport[key].split(",")
         # Remove the false split positive.
@@ -364,12 +418,22 @@
         split.pop()
         # We just delete gaia for now.
         split.pop(0)
-        statToJID = {}
         for i, part in enumerate(split):
-           statToJID[JIDs[i]] = part
-        processedGameReport[key] = statToJID
-    return processedGameReport
+          statToJID[JIDs[i]] = part
+        inProcessGameReport[key] = statToJID
+    if self.processedGameReport == {}:
+      self.processedGameReport = inProcessGameReport
 
+    players = map(lambda jid: db.query(Player).filter_by(jid=jid).first(),
+                  dict.keys(self.processedGameReport['playerStates']))
+
+    for player in players:
+      if self.processedGameReport['playerStates'][player] == "active" and inProcessGameReport['playerStates'][player] != "active":
+        for key in dict.keys(self.processedGameReport):
+          self.processedGameReport[key][player] = inProcessGameReport[key][player]
+    print(self.processedGameReport)
+    return self.processedGameReport
+
   def checkFull(self):
     """
       Searches internal database to check if enough
@@ -386,14 +450,19 @@
       for JID in self.interimJIDTracker[i]:
         if JID != None:
           numReports += 1
-      if numReports == numPlayers:
-        self.leaderboard.addAndRateGame(self.expandReport(self.interimReportTracker[i], self.interimJIDTracker[i]))
-        del self.interimJIDTracker[i]
-        del self.interimReportTracker[i]
-        length -= 1
-      else:
-        i += 1
-        self.leaderboard.lastRated = ""
+      print(self.interimJIDTracker[i])
+      print("numReports")
+      print(numReports)
+      #if numReports == numPlayers:
+      self.leaderboard.addAndRateGame(self.expandReport(self.interimReportTracker[i], self.interimJIDTracker[i]))
+      i += 1
+      del self.interimJIDTracker[i]
+      del self.interimReportTracker[i]
+      length -= 1
+      #else:
+       #i += 1
+       #self.leaderboard.lastRated = ""
+    self.processedGameReport = {}
 
   def getNumPlayers(self, rawGameReport):
     """
