Complete.Org: Mailing Lists: Archives: freeciv-dev: January 2006:
[Freeciv-Dev] Re: (PR#14274) new ranking server code
Home

[Freeciv-Dev] Re: (PR#14274) new ranking server code

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#14274) new ranking server code
From: "Mike Kaufman" <kaufman@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 8 Jan 2006 21:09:18 -0800
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=14274 >

I see that every patch that I attached to this ticket was the one that I
was committing. This patch _is_ the one I'm committing. I swear :)

o add cmdline option -R to enable
o deal with endy

-mike

Index: server/civserver.c
===================================================================
--- server/civserver.c  (revision 11419)
+++ server/civserver.c  (working copy)
@@ -127,6 +127,8 @@
       srvarg.log_filename = option; /* Never freed. */
     } else if ((option = get_option_malloc("--gamelog", argv, &inx, argc))) {
       srvarg.gamelog_filename = option; /* Never freed. */
+    } else if ((option = get_option_malloc("--Ranklog", argv, &inx, argc))) {
+      srvarg.ranklog_filename = option; /* Never freed. */
     } else if (is_option("--nometa", argv[inx])) {
       fc_fprintf(stderr, _("Warning: the %s option is obsolete.  "
                           "Use -m to enable the metaserver.\n"), argv[inx]);
@@ -243,6 +245,8 @@
     fc_fprintf(stderr,
             _("  -P, --Ppm\t\tSave ppms of the map when saving the game.\n"));
     fc_fprintf(stderr, _("  -r, --read FILE\tRead startup script FILE\n"));
+    fc_fprintf(stderr,
+              _("  -R, --Ranklog FILE\tUse FILE as ranking logfile\n"));
     fc_fprintf(stderr, _("  -v, --version\t\tPrint the version number\n"));
 #ifdef GGZ_SERVER
     fc_fprintf(stderr, _("  -z, --zone\t\tEnable GGZ mode\n"));
Index: server/score.c
===================================================================
--- server/score.c      (revision 11419)
+++ server/score.c      (working copy)
@@ -434,3 +434,205 @@
 
   fclose(fp);
 }
+
+/**************************************************************************
+  At the end of a game, figure the winners and losers of the game and
+  output to a suitable place.
+
+  The definition of winners and losers: a winner is one who is alive at the
+  end of the game and has not surrendered, or in the case of a team game, 
+  is alive or a teammate is alive and has not surrendered. A loser is
+  surrendered or dead. Exception: the winner of the spacerace and his 
+  teammates will win of course.
+
+  Barbarians do not count as winners or losers.
+
+  Games ending by endyear results in a draw, we don't rank in that case.
+**************************************************************************/
+void rank_users(void)
+{
+  FILE *fp;
+  int i;
+  enum victory_state { VS_NONE, VS_LOSER, VS_WINNER };
+  enum victory_state plr_state[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
+  struct player *spacerace_winner = NULL;
+
+  /* game ending via endyear results in a draw. We don't rank. */
+  if (game.info.year > game.info.end_year) {
+    return;
+  }
+
+  /* don't output ranking info if we haven't enabled it via cmdline */
+  if (!srvarg.ranklog_filename) {
+    return;
+  }
+
+  fp = fopen(srvarg.ranklog_filename,"w");
+
+  /* don't fail silently, at least print an error */
+  if (!fp) {
+    freelog(LOG_ERROR, "couldn't open ranking log file: \"%s\"",
+            srvarg.ranklog_filename);
+    return;
+  }
+
+  /* initialize plr_state */
+  for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
+    plr_state[i] = VS_NONE;
+  }
+
+  /* do we have a spacerace winner? */
+  players_iterate(pplayer) {
+    if (pplayer->spaceship.state == SSHIP_ARRIVED) {
+      spacerace_winner = pplayer;
+      break;
+    }
+  } players_iterate_end;
+
+  /* make this easy: if we have a spacerace winner, then treat all others
+   * who are still alive as surrendered */
+  if (spacerace_winner) {
+    players_iterate(pplayer) {
+      if (pplayer != spacerace_winner) {
+        pplayer->surrendered = TRUE;
+      }
+    } players_iterate_end;
+  }
+
+  /* first pass: locate those alive who haven't surrendered, set them to win;
+   * barbarians won't count, and everybody else is a loser for now. */
+  players_iterate(pplayer) {
+    if (is_barbarian(pplayer)) {
+      plr_state[pplayer->player_no] = VS_NONE;
+    } else if (pplayer->is_alive && !pplayer->surrendered) {
+      plr_state[pplayer->player_no] = VS_WINNER;
+    } else {
+      plr_state[pplayer->player_no] = VS_LOSER;
+    }
+  } players_iterate_end;
+
+  /* second pass: find the teammates of those winners, they win too. */
+  players_iterate(pplayer) {
+    if (plr_state[pplayer->player_no] == VS_WINNER) {
+      players_iterate(aplayer) {
+        if (aplayer->team == pplayer->team) {
+          plr_state[aplayer->player_no] = VS_WINNER;
+        }
+      } players_iterate_end;
+    }
+  } players_iterate_end;
+
+  /* write out ranking information to file */
+  fprintf(fp, "turns: %d\n", game.info.turn);
+  fprintf(fp, "winners: ");
+  players_iterate(pplayer) {
+    if (plr_state[pplayer->player_no] == VS_WINNER) {
+      fprintf(fp, "%s (%s,%s), ", pplayer->ranked_username, pplayer->name,
+                                  pplayer->username);
+    }
+  } players_iterate_end;
+  fprintf(fp, "\nlosers: ");
+  players_iterate(pplayer) {
+    if (plr_state[pplayer->player_no] == VS_LOSER) {
+      fprintf(fp, "%s (%s,%s), ", pplayer->ranked_username, pplayer->name,
+                                  pplayer->username);
+    }
+  } players_iterate_end;
+  fprintf(fp, "\n");
+
+  fclose(fp);
+}
+
+/**************************************************************************
+  At the end of a game, figure the winners and losers of the game and
+  output to a suitable place.
+
+  The definition of winners and losers: a winner is one who is alive at the
+  end of the game and has not surrendered, or in the case of a team game, 
+  is alive or a teammate is alive and has not surrendered. A loser is
+  surrendered or dead. Exception: the winner of the spacerace and his 
+  teammates will win of course.
+
+  Barbarians do not count as winners or losers.
+**************************************************************************/
+void rank_users(void)
+{
+  FILE *fp;
+  int i;
+  enum victory_state { VS_NONE, VS_LOSER, VS_WINNER };
+  enum victory_state plr_state[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
+  struct player *spacerace_winner = NULL;
+
+  fp = fopen("ranking.log","w");
+
+  /* oh well, we can fail silently */
+  if (!fp) {
+    return;
+  }
+
+  /* initialize plr_state */
+  for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
+    plr_state[i] = VS_NONE;
+  }
+
+  /* do we have a spacerace winner? */
+  players_iterate(pplayer) {
+    if (pplayer->spaceship.state == SSHIP_ARRIVED) {
+      spacerace_winner = pplayer;
+      break;
+    }
+  } players_iterate_end;
+
+  /* make this easy: if we have a spacerace winner, then treat all others
+   * who are still alive as surrendered */
+  if (spacerace_winner) {
+    players_iterate(pplayer) {
+      if (pplayer != spacerace_winner) {
+        pplayer->surrendered = TRUE;
+      }
+    } players_iterate_end;
+  }
+
+  /* first pass: locate those alive who haven't surrendered, set them to win;
+   * barbarians won't count, and everybody else is a loser for now. */
+  players_iterate(pplayer) {
+    if (is_barbarian(pplayer)) {
+      plr_state[pplayer->player_no] = VS_NONE;
+    } else if (pplayer->is_alive && !pplayer->surrendered) {
+      plr_state[pplayer->player_no] = VS_WINNER;
+    } else {
+      plr_state[pplayer->player_no] = VS_LOSER;
+    }
+  } players_iterate_end;
+
+  /* second pass: find the teammates of those winners, they win too. */
+  players_iterate(pplayer) {
+    if (plr_state[pplayer->player_no] == VS_WINNER) {
+      players_iterate(aplayer) {
+        if (aplayer->team == pplayer->team) {
+          plr_state[aplayer->player_no] = VS_WINNER;
+        }
+      } players_iterate_end;
+    }
+  } players_iterate_end;
+
+  /* write out ranking information to file */
+  fprintf(fp, "turns: %d\n", game.info.turn);
+  fprintf(fp, "winners: ");
+  players_iterate(pplayer) {
+    if (plr_state[pplayer->player_no] == VS_WINNER) {
+      fprintf(fp, "%s (%s,%s), ", pplayer->ranked_username, pplayer->name,
+                                  pplayer->username);
+    }
+  } players_iterate_end;
+  fprintf(fp, "\nlosers: ");
+  players_iterate(pplayer) {
+    if (plr_state[pplayer->player_no] == VS_LOSER) {
+      fprintf(fp, "%s (%s,%s), ", pplayer->ranked_username, pplayer->name,
+                                  pplayer->username);
+    }
+  } players_iterate_end;
+  fprintf(fp, "\n");
+
+  fclose(fp);
+}
Index: server/srv_main.c
===================================================================
--- server/srv_main.c   (revision 11419)
+++ server/srv_main.c   (working copy)
@@ -178,6 +178,7 @@
 
   srvarg.log_filename = NULL;
   srvarg.gamelog_filename = NULL;
+  srvarg.ranklog_filename = NULL;
   srvarg.load_filename[0] = '\0';
   srvarg.script_filename = NULL;
   srvarg.saves_pathname = "";
@@ -552,6 +553,16 @@
     } players_iterate_end;
   }
 
+  /* find out if users attached to players have been attached to those players
+   * for long enough. The first user to do so becomes "associated" to that
+   * player for ranking purposes. */
+  players_iterate(pplayer) {
+    if (strcmp(pplayer->ranked_username, ANON_USER_NAME) == 0
+        && pplayer->user_turns++ > TURNS_NEEDED_TO_RANK) {
+      sz_strlcpy(pplayer->ranked_username, pplayer->username);
+    }
+  } players_iterate_end;
+
   /* See if the value of fog of war has changed */
   if (is_new_turn && game.info.fogofwar != game.fogofwar_old) {
     if (game.info.fogofwar) {
@@ -1676,7 +1687,9 @@
     (void) send_server_info_to_metaserver(META_REFRESH);
 
     if (server_state != GAME_OVER_STATE && check_for_game_over()) {
-      server_state=GAME_OVER_STATE;
+      server_state = GAME_OVER_STATE;
+      /* this goes here, because we don't rank users after an /endgame */
+      rank_users();
     }
   }
 
Index: server/score.h
===================================================================
--- server/score.h      (revision 11419)
+++ server/score.h      (working copy)
@@ -21,4 +21,6 @@
 
 void save_ppm(void);
 
+void rank_users(void);
+
 #endif /* FC__SCORE_H */
Index: server/srv_main.h
===================================================================
--- server/srv_main.h   (revision 11419)
+++ server/srv_main.h   (working copy)
@@ -35,6 +35,7 @@
   /* filenames */
   char *log_filename;
   char *gamelog_filename;
+  char *ranklog_filename;
   char load_filename[512]; /* FIXME: may not be long enough? use MAX_PATH? */
   char *script_filename;
   char *saves_pathname;
Index: server/connecthand.c
===================================================================
--- server/connecthand.c        (revision 11419)
+++ server/connecthand.c        (working copy)
@@ -437,6 +437,7 @@
 
   if (!pconn->observer) {
     sz_strlcpy(pplayer->username, pconn->username);
+    pplayer->user_turns = 0; /* reset for a new user */
     pplayer->is_connected = TRUE;
   }
 
Index: server/stdinhand.c
===================================================================
--- server/stdinhand.c  (revision 11419)
+++ server/stdinhand.c  (working copy)
@@ -64,6 +64,7 @@
 #include "ruleset.h"
 #include "sanitycheck.h"
 #include "savegame.h"
+#include "score.h"
 #include "sernet.h"
 #include "settings.h"
 #include "srv_main.h"
@@ -3636,7 +3637,6 @@
                    caller->player->name);
     caller->player->surrendered = TRUE;
     if (check_for_game_over()) {
-      server_state = GAME_OVER_STATE;
       force_end_of_sniff = TRUE;
     }
     return TRUE;
Index: server/savegame.c
===================================================================
--- server/savegame.c   (revision 11419)
+++ server/savegame.c   (working copy)
@@ -1872,6 +1872,9 @@
   sz_strlcpy(plr->name, secfile_lookup_str(file, "player%d.name", plrno));
   sz_strlcpy(plr->username,
             secfile_lookup_str_default(file, "", "player%d.username", plrno));
+  sz_strlcpy(plr->ranked_username,
+            secfile_lookup_str_default(file, "", "player%d.ranked_username", 
+             plrno));
 
   /* 1.15 and later versions store nations by name.  Try that first. */
   p = secfile_lookup_str_default(file, NULL, "player%d.nation", plrno);
@@ -2691,6 +2694,8 @@
 
   secfile_insert_str(file, plr->name, "player%d.name", plrno);
   secfile_insert_str(file, plr->username, "player%d.username", plrno);
+  secfile_insert_str(file, plr->ranked_username, "player%d.ranked_username",
+                     plrno);
   secfile_insert_str(file, get_nation_name_orig(plr->nation),
                     "player%d.nation", plrno);
   /* 1.15 and later won't use the race field, they key on the nation string 
Index: common/player.c
===================================================================
--- common/player.c     (revision 11419)
+++ common/player.c     (working copy)
@@ -177,6 +177,8 @@
 
   sz_strlcpy(plr->name, ANON_PLAYER_NAME);
   sz_strlcpy(plr->username, ANON_USER_NAME);
+  sz_strlcpy(plr->ranked_username, ANON_USER_NAME);
+  plr->user_turns = 0;
   plr->is_male = TRUE;
   plr->government = NULL;
   plr->target_government = NULL;
Index: common/player.h
===================================================================
--- common/player.h     (revision 11419)
+++ common/player.h     (working copy)
@@ -157,6 +157,8 @@
   int player_no;
   char name[MAX_LEN_NAME];
   char username[MAX_LEN_NAME];
+  char ranked_username[MAX_LEN_NAME]; /* the user who will be ranked */
+  int user_turns;            /* number of turns this user has played */
   bool is_male;
   struct government *government; /* may be NULL in pregame */
   struct government *target_government; /* may be NULL */
Index: common/game.h
===================================================================
--- common/game.h       (revision 11419)
+++ common/game.h       (working copy)
@@ -50,6 +50,10 @@
 #define CONTAMINATION_POLLUTION 1
 #define CONTAMINATION_FALLOUT   2
 
+/* The number of turns that the first user needs to be attached to a 
+ * player for that user to be ranked as that player */
+#define TURNS_NEEDED_TO_RANK 10
+
 struct civ_game {
   struct packet_game_info info;
   struct government *government_when_anarchy;

[Prev in Thread] Current Thread [Next in Thread]