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

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

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#14274) new ranking server code
From: "Mike Kaufman" <kaufman@xxxxxxxxxxxxxxxxxxxxxx>
Date: Tue, 11 Oct 2005 21:07:18 -0700
Reply-to: bugs@xxxxxxxxxxx

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

Attached is a first draft to replace the snafu that was the ranking code.
Currently, the gamelog output serves as the input to a perl script on
pubserver. That script is horribly complicated and frankly I don't trust
it for day-in/day-out use. I would guess that this patch would reduce the
script by about 500 lines.

You can see my thoughts on most of this at:
http://www.freeciv.org/index.php/Pubserver_Internals

The idea here is to skip a couple of steps. Instead of parsing the gamelog
to determine (and this is not easy) which user is the winner and which
users are the losers, the server keeps track of this during the game and
spits out the answer on game completion.

Disadvantages:
o puts ranking policy into the server.
o the simplicity of the output means it's difficult to change ranking
  policy once this change goes into effect.
o requires more limits to be put onto usernames (no commas or brackets (we
  can choose which of { or [ or ( to disallow))

Advantages:
o mandated ranking policy is easy-to-understand ranking. (YMMV)
o makes ranking script quite simple -> easy maintenance, more transparent.
o able to remove lots of server code (no more icky gamelog).
o a big step to a working ranking system.

Per has stated that he would like the output of the do_rank_users()
function to be the mysql database. I think this is useless as we'll need a
script anyway to actually update the ranking tables, and working with a
dead simple flat file is a lot easier than dealing with mysql. We also
don't add pseudo-dependencies to the server.

step 1. review this patch, decide on plan of action
step 2. decide on flat file or mysql output
step 3. write pubserver script to handle ranking with output
step 4. commit patch
step 5. write second patch so that users can tell if they are the ones to
        be ranked if they finish the game off (requires client changes I
        imagine.
step 6. we're golden

-mike

Index: server/score.c
===================================================================
--- server/score.c      (revision 11101)
+++ server/score.c      (working copy)
@@ -487,3 +487,76 @@
 
   return count;
 }
+
+/**************************************************************************
+  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.
+
+  Barbarians do not count as winners or losers.
+**************************************************************************/
+void do_rank_users(void)
+{
+  FILE *fp;
+  int i;
+  enum victory_state { VS_UNKNOWN = -1, VS_LOSER, VS_WINNER, VS_NONE };
+  enum victory_state plr_state[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
+
+  fp = fopen("ranking.log","w");
+
+  /* initialize plr_state */
+  for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
+    plr_state[i] = VS_UNKNOWN;
+  }
+
+  /* first pass: locate those alive who haven't surrendered. set them to win */
+  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;
+    }
+  } 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;
+
+  /* third pass: everybody else is a loser. */
+  for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
+    if (plr_state[i] != VS_WINNER && plr_state[i] != VS_NONE) {
+      plr_state[i] = VS_LOSER;
+    }
+  }
+
+  /* write out XXX: put mysql code right here */
+  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 11101)
+++ server/srv_main.c   (working copy)
@@ -488,6 +488,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) {
@@ -1611,6 +1621,7 @@
 
     if (server_state != GAME_OVER_STATE && is_game_over()) {
       server_state=GAME_OVER_STATE;
+      do_rank_users();
     }
   }
 
Index: server/score.h
===================================================================
--- server/score.h      (revision 11101)
+++ server/score.h      (working copy)
@@ -19,4 +19,6 @@
 
 int total_player_citizens(const struct player *pplayer);
 
+void do_rank_users(void);
+
 #endif /* FC__SCORE_H */
Index: server/connecthand.c
===================================================================
--- server/connecthand.c        (revision 11101)
+++ server/connecthand.c        (working copy)
@@ -697,6 +697,7 @@
 
   if (!pconn->observer) {
     sz_strlcpy(pplayer->username, pconn->username);
+    pplayer->user_turns = 0; /* reset for a new user */
     pplayer->is_connected = TRUE;
   }
 
Index: common/player.c
===================================================================
--- common/player.c     (revision 11101)
+++ common/player.c     (working copy)
@@ -114,6 +114,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 11101)
+++ common/player.h     (working copy)
@@ -152,6 +152,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 11101)
+++ 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]
  • [Freeciv-Dev] (PR#14274) new ranking server code, Mike Kaufman <=