3hr IC vs Rix game

Tactical advice, How-to, Post-mortem, etc.
CronoDroid
Posts: 4606
Joined: Sun Nov 06, 2005 8:00 am
Contact:

Post by CronoDroid »

Death3D wrote:QUOTE (Death3D @ Oct 30 2008, 06:44 PM) What program to use to read an XML file coherently and not as a list of unsorted stats?
Madpeople has a program that turns it into one of the endgame allegiance stats thing, I don't know where it is but I'm sure either madpeople or Adept could tell you.
badpazzword
Posts: 3627
Joined: Thu Jan 12, 2006 8:00 am
Contact:

Post by badpazzword »

CODE#!/usr/bin/python
from __future__ import division
from xml.dom.minidom import parse
import time

class nick(unicode):
def detokenize(self):
output = self[:]
# output = output.replace("*", "Squad Leader ")
# output = output.replace("^", "Assistant Squad Leader ")
# output = output.replace("+", "Zone Leader ")
# output = output.replace("$", "Hacker Extraordinaire ")
return output

def tag(self):
if '@' not in self:
return None
else:
atPos = str.index('@')
return self[atPos:]

class Player(object):
def __init__(self, xmlPlayer, _teamNo_):
readTag = (lambda x: xmlPlayer.getElementsByTagName(x)[0].firstChild.data)
self.name = nick(readTag("Name"))
self.isCommander = (readTag("IsCommander") == "true")
self.rank = int(readTag("Rank"))
self.assists = int(readTag("Assists"))
self.baseCaptures = int(readTag("BaseCaptures"))
self.baseKills = int(readTag("BaseKills"))
self.deaths = int(readTag("Deaths"))
self.ejects = int(readTag("Ejections"))
self.kills = int(readTag("Kills"))
self.score = float(readTag("Score"))
self.timePlayed = int(float(readTag("TimePlayed")))
self.killsperhr = 3600 * self.kills / self.timePlayed
self.pointsperhr = 3600 * self.score / self.timePlayed
self._teamNo_ = _teamNo_

def __repr__(self):
return "<player %s(%d)>" % (
self.name,
self.rank,
)

def __str__(self):
return """%-28s %24s.
Kills: %3d. Ejects: %3d. Base kills: %3d.
Assists: %3d. Deaths: %3d. Base captures: %3d.
""" % \
((self.isCommander and "Commander " or "Pilot ") + self.name.detokenize(),
"%d points in %s" % (self.score, strTime(self.timePlayed)),
self.kills, self.ejects, self.baseKills,
self.assists, self.deaths, self.baseCaptures,
)

class Team(object):

def __init__(self, xmlTeam, xmlPlayers):
readTag = (lambda x: xmlTeam.getElementsByTagName(x)[0].firstChild.data)
self.faction = readTag("Faction")
self._teamNo_ = readTag("TeamNumber")
try:
self.name = readTag("Name")
except:
self.name = "Anonymous Cowards %d" % (int(self._teamNo_)+1)
self.players = [Player(item, self._teamNo_) for item in xmlPlayers]
self.heloSum = sum([player.score for player in self.players])


def __repr__(self):
return "<%s team %s (%d players)>" % (
self.faction.lower(),
self.name.lower(),
len(self.players)
)

def __str__(self):
return "%s team \"%s\": %s" % (self.faction, self.name, _(self.players))

def __getitem__(self, x): return self.players[x]

def __len__(self):
return max([player.timePlayed for player in self.players])

def most(self, what):
maxStat = max([getattr(player, what) for player in self.players])
#Special case
if (maxStat == 0) and (what == "ejects"):
return self.most("deaths")
return (maxStat, [player for player in self.players if getattr(player, what) == maxStat])

def commanders(self):
return [player for player in self.players if player.isCommander]


class Game(object):

def __init__(self, xmlGame):
'''Create a game object from an Allegiance xml scores file.'''
readTag = (lambda x: xmlGame.getElementsByTagName(x)[0].firstChild.data)

self.time = time.strptime(readTag("Date"), "%m/%d/%y %H:%M:%S")
self.server = readTag("Server")
self.core = readTag("Core")
self.reason = readTag("GameOverReason") #.replace(" Adv ", " Advanced ")
self.teams = []

xmlPlayers = xmlGame.getElementsByTagName("PlayerScore")
teamNo = (lambda x: x.getElementsByTagName("TeamNumber")[0].firstChild.data)
#Works both for teams and players. Woot!

for xmlTeam in xmlGame.getElementsByTagName("Team"):
teamPlayers = [xmlFoo for xmlFoo in xmlPlayers if teamNo(xmlTeam) == teamNo(xmlFoo)]
self.teams.append(Team(xmlTeam, teamPlayers))

def __repr__(self):
return "<%s game (%s, %d teams)>" % (
self.server,
time.strftime("%a %b %d %H:%M:%S %Y", self.time),
len(self.teams)
)

def __len__(self):
#No direct way to compute this, that I know of.
#Solution:
return max(map(len, self.teams))

def __getitem__(self, x):
return self.teams[x]

def most(self, what):
teamTopGuns = [team.most(what) for team in self.teams]
maxStat = max([item[0] for item in teamTopGuns])
topGuns = []
topGuns.extend([item[1][0] for item in teamTopGuns if item[0] == maxStat])
return (maxStat, topGuns)

def parseGameData(filename):
document = parse(open(filename))
thisGame = Game(document)
return thisGame

def strTime(seconds):
minute = (seconds // 60) % 60
hour = (seconds // 3600) % 60
second = (seconds) % 60

output = u""
showSeconds = False
if hour:
pluralS = (hour == 1) and ("hour") or ("hours")
output += u"%d %s " % (hour, pluralS)
else:
showSeconds = True
if minute:
pluralS = (minute == 1) and ("minute") or ("minutes")
output += u"%d %s " % (minute, pluralS)
else:
showSeconds = True
if second and showSeconds:
pluralS = (second == 1) and ("second") or ("seconds")
output += u"%d %s " % (second, pluralS)

if output == u"":
return "%d seconds" % seconds
else:
return output.strip()

def sortPlayers(x, y):
if x.isCommander != y.isCommander:
if x.isCommander: return -1
else: return 1
else:
timeFactor = -cmp(x.timePlayed, y.timePlayed)
if timeFactor: return timeFactor
return -cmp(x.score, y.score)

def _(players):
players.sort(sortPlayers)
players = [player.name.detokenize() for player in players]
return ", ".join(players)

if __name__ == '__main__':
#usage: python -i allegXMLreader.py
import sys

filename = sys.argv[1]
thisGame = parseGameData(filename)

print u"%s." % time.strftime("%A, %B %d %Y", thisGame.time)
teamNames = [team.name for team in thisGame.teams]
print u" versus ".join(teamNames) + "."

if "--top" in sys.argv:
for team in thisGame.teams:
topGuns = team.most("kills")
topPoints = team.most("score")
topPods = team.most("ejects")
print """%s, commanded team "%s" (%s).
Top kills: %s with %d.
Top ejects: %s with %d.
Top points: %s with %d.""" % \
(_(team.commanders()), team.name, team.faction,
_(topGuns[1]), topGuns[0],
_(topPods[1]), topPods[0],
_(topPoints[1]), topPoints[0],
)

print u"After %s, %s" % (strTime(len(thisGame)), thisGame.reason)

if "--players" in sys.argv:
for team in thisGame.teams:
print "===========// Team %s //===========" % team.name
players = team.players
players.sort(sortPlayers)
for player in team:
print player

Here's something I quickly hacked together as a part of the. Hopefully it works in Windows too. In its current form, you'd have to do the following:

1. Get Python 2.5
2. Copy paste into "xmlReader.py" somewhere useful.
3. Get a command prompt
4. cd C:\Python25\
4. Drag the xmlReader.py file into the command prompt
5. Drag the xml file into the command prompt
6. Type --top --players
7. Press Enter
8. Scroll up and read from the beginning the dumped content.

Yeah, a pain. I've built an interface to Zenity, a Linux UI-from-the-commandline tool, and to WikiMarkup for copy paste on the wiki, but I can't be currently arsed to actually learn gui programming. The foundation's there though :D
Have gaming questions? Get expert answers! Image Image
Adept
Posts: 8660
Joined: Thu Sep 27, 2007 12:53 pm
Location: Turku, Finland

Post by Adept »

Death3D wrote:QUOTE (Death3D @ Oct 31 2008, 03:44 AM) What program to use to read an XML file coherently and not as a list of unsorted stats?
Madpeople's widget is the best, in my opinion. Can be found in his blog.
ImageImageImageImageImage
<bp|> Maybe when I grow up I can be a troll like PsycH
<bp|> or an obsessive compulsive paladin of law like Adept
fwiffo
Posts: 1525
Joined: Fri Sep 07, 2007 4:38 am
Location: CA, USA
Contact:

Post by fwiffo »

hi badp,

your python script is pretty cool, i kinda reinvented the wheel a bit and parsed the xml using perl instead (my preferred weapon of choice) and took it one step further: i stuff all the parsed data into a database.

this project is about halfway done, i've got a couple of things to implement to give the script a bit more intelligence, but the basic functionality is already working.

the idea here is to mass aggregate all the stats from a whole bunch of user submittted xml files and produce something similar to the Leaderboard, except with more features and maybe a bit more granularity on the different statistics.

once complete, regular users can just upload a zip file of their saved xml to my webserver and my script can take that data and store it into the database which can then be queried by anyone.

my question is, do you think a lot of alleg players save their after-game xml files and out of that fraction of people, will they bother to upload those files to me?

i've got a sizable chunk of xmls saved, but obviously, statistically speaking, the more samples i get, the better and more useful the database will become, so i'd like to gauge the interest and see if i should continue on.

i save my source code in google's svn:
http://code.google.com/p/fleetcommand/source/checkout

you can browse the work i've done so far here:
http://code.google.com/p/fleetcommand/sour...l/parsestats.pl

if you want to make it work on your local machine, you'll also want to define the structure of your mysql database:
http://code.google.com/p/fleetcommand/sour...gxml/struct.sql
Last edited by fwiffo on Fri Oct 31, 2008 10:06 pm, edited 1 time in total.
Image
ImageImageImageImageImageImageImageImage
A Spathi's Axiom for Survival: "The only brave Spathi is a dead Spathi. RUN YOU FOOLS!"
FreeBeer
Posts: 10902
Joined: Tue Dec 27, 2005 8:00 am
Location: New Brunswick, Canada

Post by FreeBeer »

fwiffo wrote:QUOTE (fwiffo @ Oct 31 2008, 07:04 PM) my question is, do you think a lot of alleg players save their after-game xml files and out of that fraction of people, will they bother to upload those files to me?

I think a number of people would... at least for a while. You know how it goes with shiny new toys... :D The only issue I can think of is a way to ensure duplicates are weeded out, but I imagine that you've already given that due consideration.
[img]http://www.freeallegiance.org/forums/st ... erator.gif" alt="IPB Image">

chown -R us base
fwiffo
Posts: 1525
Joined: Fri Sep 07, 2007 4:38 am
Location: CA, USA
Contact:

Post by fwiffo »

yea, solving duplication problem with a hash of the items that make a particular game unique:

Server,GameOverReason,Date,Core

from the gameinfo section of the xml.

if that turns out not to be enough, i can throw in the first couple of scores/stats from the playerinfo section too, that ought to make it unique enough.
Image
ImageImageImageImageImageImageImageImage
A Spathi's Axiom for Survival: "The only brave Spathi is a dead Spathi. RUN YOU FOOLS!"
FreeBeer
Posts: 10902
Joined: Tue Dec 27, 2005 8:00 am
Location: New Brunswick, Canada

Post by FreeBeer »

I wonder... does the xml change based on how the person has stuff sorted? If it does, then I can see your secondary test failing. (I think).
[img]http://www.freeallegiance.org/forums/st ... erator.gif" alt="IPB Image">

chown -R us base
fwiffo
Posts: 1525
Joined: Fri Sep 07, 2007 4:38 am
Location: CA, USA
Contact:

Post by fwiffo »

yea i dont know if its sorted in some predetermined fashion when the xml is generated, but thats a good thing to watch out for, i guess alternatively i can just pick the stats of the top 3 highest scorers and use them in the hash.
Image
ImageImageImageImageImageImageImageImage
A Spathi's Axiom for Survival: "The only brave Spathi is a dead Spathi. RUN YOU FOOLS!"
badpazzword
Posts: 3627
Joined: Thu Jan 12, 2006 8:00 am
Contact:

Post by badpazzword »

I've been toying with such an idea as well. How would you handle forgeries?
Have gaming questions? Get expert answers! Image Image
fwiffo
Posts: 1525
Joined: Fri Sep 07, 2007 4:38 am
Location: CA, USA
Contact:

Post by fwiffo »

a good point. the simple answer is that i cant. what algorithms i can come up with to try to catch forgeries would be way beyond the scope of this exercise. the only thing i can think of is to limit the submissions to come from only "trusted" sources.

it would be great if i could get that xml directly from the alleg servers after every game, but i guess there's only a small chance of that happening.

any suggestions to resolve this stumbling block?
Last edited by fwiffo on Fri Oct 31, 2008 11:26 pm, edited 1 time in total.
Image
ImageImageImageImageImageImageImageImage
A Spathi's Axiom for Survival: "The only brave Spathi is a dead Spathi. RUN YOU FOOLS!"
Post Reply