AI Testing: AI batch testing scripts and web interface

This commit is contained in:
Iurii Chernyi 2009-04-28 00:43:55 +00:00
parent f85264e315
commit 535fb6d8b0
5 changed files with 642 additions and 0 deletions

17
utils/ai_test/ai_test.cfg Normal file
View file

@ -0,0 +1,17 @@
[default]
path_to_wesnoth_binary=../../wesnoth-debug ../..
arguments_to_wesnoth_binary=--log-info=ai/testing --nogui --multiplayer --controller1=ai --controller2=ai
number_of_tests=10000
ai_config1=ai/ais/formula_ai.cfg
ai_config2=ai/ais/default_ai.cfg
faction1=
faction2=
db_ip=127.0.0.1
db_port=5432
db_name=org.wesnoth.ai.test
db_user=wesnoth_ai_test_user
db_pass=PASSWORD
map1=multiplayer_Weldyn_Channel
map2=multiplayer_The_Freelands
map3=multiplayer_Den_of_Onis
map4=multiplayer_Fallenstar_Lake

185
utils/ai_test/ai_test.py Executable file
View file

@ -0,0 +1,185 @@
#!/usr/bin/env python
from subprocess import Popen,PIPE
from time import clock, time
from pyPgSQL import PgSQL
import ConfigParser
import os
import string
import random
class GameResult:
ai_config1 = ''
ai_config2 = ''
ai_ident1 = ''
ai_ident2 = ''
duration = '0'
faction1 = ''
faction2 = ''
is_success = 'false'
local_modifications = 'false'
map = ''
svn_release = '0'
test = 'default'
turn = '0'
version_string = ''
winner_side = '0'
def __init__(self,_ai_config1,_ai_config2,_faction1,_faction2,_map,_test):
self.ai_config1 = _ai_config1
self.ai_config2 = _ai_config2
self.faction1 = _faction1
self.faction2 = _faction2
self.map = _map
self.test = _test
def filter_non_printable(str):
return ''.join(c for c in str if ord(c) > 31 or ord(c) == 9)
def construct_command_line(cfg,ai1,ai2,f1,f2,map):
wesnoth = cfg.get('default','path_to_wesnoth_binary')
options= cfg.get('default','arguments_to_wesnoth_binary')
ai_config1='--ai_config1='+ai1
ai_config2='--ai_config2='+ai2
if (map==''):
optmap=''
else:
optmap='--scenario='+map
return wesnoth+' '+options+' '+optmap+' '+ai_config1+' '+ai_config2
def do_filter(str,substring):
n = str.find(substring)
if (n>-1):
return n,str[n+len(substring):].strip()
return n,''
def run_game(cfg,game_result):
command_line = construct_command_line(cfg,game_result.ai_config1,game_result.ai_config2, game_result.faction1, game_result.faction2, game_result.map)
print 'Running: '+command_line
start = time()
p = Popen(command_line, shell=True, stdout=PIPE, stderr=PIPE)
outlines = p.stdout.readlines()
outerrlines = p.stderr.readlines()
print 'Finished'
for line in outerrlines:
str = filter_non_printable(line.strip())
n,s = do_filter(str,'info ai/testing: WINNER:')
if (n>-1):
#print 'AND THE WINNER IS: '+s
game_result.winner_side = s
game_result.is_success = 'true'
continue
n,s = do_filter(str,'info ai/testing: VERSION:')
if (n>-1):
#print 'AND THE VERSION IS: '+s
game_result.version_string = s
n1 = s.rfind('(')
n2 = s.rfind(')')
if ((n1>-1) and (n2>-1) and (n2>n1)):
sz = s[n1+1:n2]
#parse local_modifications
#parse svn_release
game_result.svn_release = sz
continue
n,s = do_filter(str,'info ai/testing: VICTORY_TURN:')
if (n>-1):
#print 'AND THE VICTORY_TURN IS: '+s
game_result.turn = s
continue
n,s = do_filter(str,'info ai/testing: AI_IDENTIFIER1:')
if (n>-1):
#print 'AND THE AI_IDENTIFIER1 IS: '+s
game_result.ai_ident1 = s.strip()
continue
n,s = do_filter(str,'info ai/testing: AI_IDENTIFIER2:')
if (n>-1):
#print 'AND THE AI_IDENTIFIER2 IS: '+s
game_result.ai_ident2 = s.strip()
continue
n,s = do_filter(str,'info ai/testing: FACTION1:')
if (n>-1):
#print 'AND THE FACTION1 IS: '+s
game_result.faction1 = s
continue
n,s = do_filter(str,'info ai/testing: FACTION2:')
if (n>-1):
#print 'AND THE FACTION2 IS: '+s
game_result.faction2 = s
continue
game_result.duration = time() - start
if (game_result.is_success=='false'):
print 'Warning: not success!'
print '===================='
print 'stderr:'
for line in outerrlines:
print filter_non_printable(line.strip())
print 'stdout:'
for line in outlines:
print filter_non_printable(line.strip())
print '===================='
return game_result
def save_result(cfg,game_result):
print 'Saving to DB....'
query = 'insert into game(ai_config1,ai_config2,ai_ident1,ai_ident2,duration,faction1,faction2,is_success,local_modifications,map,svn_release,test,turn,version_string,winner_side) values (%s,%s,%s,%s,cast(%s as double precision),%s,%s,cast(%s as boolean),cast(%s as boolean),%s,cast(%s as int),%s,cast(%s as int),%s,cast(%s as int))'
db_ip = cfg.get('default','db_ip')
db_port = cfg.getint('default','db_port')
db_name = cfg.get('default','db_name')
db_user = cfg.get('default','db_user')
db_pass = cfg.get('default','db_pass')
dbconnection = PgSQL.connect(database=db_name,host=db_ip,port=db_port,user=db_user,password=db_pass)
cu = dbconnection.cursor()
cu.execute(query, game_result.ai_config1, game_result.ai_config2, game_result.ai_ident1, game_result.ai_ident2, game_result.duration, game_result.faction1, game_result.faction2, game_result.is_success, game_result.local_modifications, game_result.map, game_result.svn_release, game_result.test, game_result.turn, game_result.version_string, game_result.winner_side)
cu.execute('commit')
dbconnection.close()
print 'Saved to DB'
def maps(cfg):
mp = 1
while 1:
try:
yield cfg.get('default','map'+`mp`);
mp= mp+1
except:
return
def tests(cfg):
ai1=cfg.get('default','ai_config1').strip()
ai2=cfg.get('default','ai_config2').strip()
f1=cfg.get('default','faction1').strip()
f2=cfg.get('default','faction2').strip()
n=cfg.getint('default','number_of_tests')
maplist = []
for map in maps(cfg):
maplist.append(map)
random.seed()
for i in range(0, n):
map = random.choice(maplist)
d = random.randint(0,1)
print 'TEST: map '+map+' i='+str(i)+' d='+str(d)
if (d==0):
game_result = GameResult(ai1,ai2,f1,f2,map,'default')
else:
game_result = GameResult(ai2,ai1,f2,f1,map,'default')
yield game_result
# main
cfg = ConfigParser.ConfigParser()
cfg.read('ai_test.cfg')
for test in tests(cfg):
game_result = run_game(cfg,test)
save_result(cfg,game_result)

View file

@ -0,0 +1,188 @@
--
-- PostgreSQL database dump
--
-- Started on 2009-04-28 03:24:33 EEST
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
--
-- TOC entry 296 (class 2612 OID 45054)
-- Name: plpgsql; Type: PROCEDURAL LANGUAGE; Schema: -; Owner: pgsql
--
CREATE PROCEDURAL LANGUAGE plpgsql;
ALTER PROCEDURAL LANGUAGE plpgsql OWNER TO pgsql;
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
--
-- TOC entry 1469 (class 1259 OID 44782)
-- Dependencies: 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 6
-- Name: game; Type: TABLE; Schema: public; Owner: wesnoth_ai_test_user; Tablespace:
--
CREATE TABLE game (
id bigint NOT NULL,
svn_release integer DEFAULT 0 NOT NULL,
datetime timestamp with time zone DEFAULT now() NOT NULL,
winner_side integer DEFAULT 0 NOT NULL,
ai_config1 text DEFAULT ''::text NOT NULL,
ai_config2 text DEFAULT ''::text NOT NULL,
local_modifications boolean DEFAULT false NOT NULL,
turn integer DEFAULT 1 NOT NULL,
ai_ident1 text DEFAULT ''::text NOT NULL,
ai_ident2 text DEFAULT ''::text NOT NULL,
is_success boolean DEFAULT true NOT NULL,
version_string text DEFAULT ''::text NOT NULL,
duration double precision DEFAULT 0 NOT NULL,
map text DEFAULT ''::text NOT NULL,
faction1 text DEFAULT ''::text NOT NULL,
faction2 text DEFAULT ''::text NOT NULL,
test text DEFAULT 'default'::text NOT NULL,
CONSTRAINT winner_side_gte_0 CHECK ((winner_side >= 0))
);
ALTER TABLE public.game OWNER TO wesnoth_ai_test_user;
--
-- TOC entry 1470 (class 1259 OID 45085)
-- Dependencies: 1546 6
-- Name: games_side; Type: VIEW; Schema: public; Owner: wesnoth_ai_test_user
--
CREATE VIEW games_side AS
SELECT game.id, game.svn_release, game.datetime, game.duration, game.map, 1 AS my_side, CASE WHEN (game.winner_side = 1) THEN 1 WHEN (game.winner_side = 2) THEN -1 ELSE 0 END AS outcome, CASE WHEN (game.winner_side = 1) THEN 1 ELSE 0 END AS win, CASE WHEN (game.winner_side = 0) THEN 1 ELSE 0 END AS draw, CASE WHEN (game.winner_side = 2) THEN 1 ELSE 0 END AS loss, CASE WHEN (game.winner_side = 1) THEN game.turn ELSE 0 END AS win_turns, CASE WHEN (game.winner_side = 2) THEN game.turn ELSE 0 END AS loss_turns, game.is_success, game.version_string, game.ai_config1 AS ai_config_me, game.ai_config2 AS ai_config_enemy, game.ai_ident1 AS ai_ident_me, game.ai_ident2 AS ai_ident_enemy, game.local_modifications, game.turn, game.faction1 AS faction_me, game.faction2 AS faction_enemy FROM game WHERE (game.svn_release <> 0) UNION SELECT game.id, game.svn_release, game.datetime, game.duration, game.map, 2 AS my_side, CASE WHEN (game.winner_side = 1) THEN -1 WHEN (game.winner_side = 2) THEN 1 ELSE 0 END AS outcome, CASE WHEN (game.winner_side = 2) THEN 1 ELSE 0 END AS win, CASE WHEN (game.winner_side = 0) THEN 1 ELSE 0 END AS draw, CASE WHEN (game.winner_side = 1) THEN 1 ELSE 0 END AS loss, CASE WHEN (game.winner_side = 2) THEN game.turn ELSE 0 END AS win_turns, CASE WHEN (game.winner_side = 1) THEN game.turn ELSE 0 END AS loss_turns, game.is_success, game.version_string, game.ai_config2 AS ai_config_me, game.ai_config1 AS ai_config_enemy, game.ai_ident2 AS ai_ident_me, game.ai_ident1 AS ai_ident_enemy, game.local_modifications, game.turn, game.faction1 AS faction_me, game.faction2 AS faction_enemy FROM game WHERE (game.svn_release <> 0);
ALTER TABLE public.games_side OWNER TO wesnoth_ai_test_user;
--
-- TOC entry 20 (class 1255 OID 45064)
-- Dependencies: 296 6
-- Name: avg_from(bigint, bigint); Type: FUNCTION; Schema: public; Owner: pgsql
--
CREATE FUNCTION avg_from(bigint, bigint) RETURNS double precision
AS $_$
BEGIN
IF $2=0 THEN
RETURN 0;
ELSE
RETURN cast($1 as double precision)/$2;
END IF;
END;
$_$
LANGUAGE plpgsql IMMUTABLE;
ALTER FUNCTION public.avg_from(bigint, bigint) OWNER TO pgsql;
--
-- TOC entry 1468 (class 1259 OID 44780)
-- Dependencies: 1469 6
-- Name: game_id_seq; Type: SEQUENCE; Schema: public; Owner: wesnoth_ai_test_user
--
CREATE SEQUENCE game_id_seq
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
ALTER TABLE public.game_id_seq OWNER TO wesnoth_ai_test_user;
--
-- TOC entry 1765 (class 0 OID 0)
-- Dependencies: 1468
-- Name: game_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: wesnoth_ai_test_user
--
ALTER SEQUENCE game_id_seq OWNED BY game.id;
--
-- TOC entry 1738 (class 2604 OID 44785)
-- Dependencies: 1469 1468 1469
-- Name: id; Type: DEFAULT; Schema: public; Owner: wesnoth_ai_test_user
--
ALTER TABLE game ALTER COLUMN id SET DEFAULT nextval('game_id_seq'::regclass);
--
-- TOC entry 1757 (class 2606 OID 44794)
-- Dependencies: 1469 1469
-- Name: pk_game; Type: CONSTRAINT; Schema: public; Owner: wesnoth_ai_test_user; Tablespace:
--
ALTER TABLE ONLY game
ADD CONSTRAINT pk_game PRIMARY KEY (id);
--
-- TOC entry 1762 (class 0 OID 0)
-- Dependencies: 6
-- Name: public; Type: ACL; Schema: -; Owner: pgsql
--
REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM pgsql;
GRANT ALL ON SCHEMA public TO pgsql;
GRANT ALL ON SCHEMA public TO PUBLIC;
--
-- TOC entry 1763 (class 0 OID 0)
-- Dependencies: 1469
-- Name: game; Type: ACL; Schema: public; Owner: wesnoth_ai_test_user
--
REVOKE ALL ON TABLE game FROM PUBLIC;
REVOKE ALL ON TABLE game FROM wesnoth_ai_test_user;
GRANT ALL ON TABLE game TO wesnoth_ai_test_user;
GRANT SELECT ON TABLE game TO wesnoth_ai_test_viewer;
--
-- TOC entry 1764 (class 0 OID 0)
-- Dependencies: 1470
-- Name: games_side; Type: ACL; Schema: public; Owner: wesnoth_ai_test_user
--
REVOKE ALL ON TABLE games_side FROM PUBLIC;
REVOKE ALL ON TABLE games_side FROM wesnoth_ai_test_user;
GRANT ALL ON TABLE games_side TO wesnoth_ai_test_user;
GRANT SELECT ON TABLE games_side TO wesnoth_ai_test_viewer;
--
-- TOC entry 1766 (class 0 OID 0)
-- Dependencies: 1468
-- Name: game_id_seq; Type: ACL; Schema: public; Owner: wesnoth_ai_test_user
--
REVOKE ALL ON SEQUENCE game_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE game_id_seq FROM wesnoth_ai_test_user;
GRANT ALL ON SEQUENCE game_id_seq TO wesnoth_ai_test_user;
GRANT SELECT ON SEQUENCE game_id_seq TO wesnoth_ai_test_viewer;
-- Completed on 2009-04-28 03:24:36 EEST
--
-- PostgreSQL database dump complete
--

49
utils/ai_test/readme.txt Normal file
View file

@ -0,0 +1,49 @@
/*
AI Batch testing suite
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
REQUIRES:
Wesnoth
Postgresql database for storing data
PHP-enabled web server for web frontend
INSTALLATION:
1. Create a role, two users and a database - one for uploader script with INSERT priv (and ability to use the sequence used for generating IDs), and another for web frontend with SELECT priv.
---------------------
CREATE ROLE wesnoth_ai_test_viewer
NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE;
CREATE ROLE wesnoth_ai_test_user LOGIN
PASSWORD 'YOUR_PASSWORD_FOR_TEST_USER'
NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE;
GRANT wesnoth_ai_test_viewer TO wesnoth_ai_test_user;
CREATE ROLE wesnoth_ai_test_viewer_impl LOGIN
PASSWORD 'YOUR_PASSWORD_FOR_WEB_FRONTEND_USER'
NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE;
GRANT wesnoth_ai_test_viewer TO wesnoth_ai_test_viewer_impl;
CREATE DATABASE "org.wesnoth.ai.test"
WITH OWNER = wesnoth_ai_test_user
ENCODING = 'UTF8';
---------------------
2. Restore ai_test_db.backup to that newly created DB to create the DB schema and set privilegies.
3. place wesnoth_ai_test.php at a php-enabled web server
4. Modify passwords/paths in ai_test.cfg and wesnoth_ai_test.php

View file

@ -0,0 +1,203 @@
<html>
<head>
<title>Wesnoth AI Testing Statistics</title>
</head>
<body>
<?php
$database = pg_connect("host=127.0.0.1 dbname=org.wesnoth.ai.test user=wesnoth_ai_test_viewer_impl password=PASSWORD");
if (!$database) {
print("Connection Failed.");
exit;
} else {
# print("Connection Ok!");
}
?>
<h2>Latest svn AI wins % graph:</h2>
<?php
$query = "select ai_ident_me,avg_from(sum(win)*100,count(*))::bigint as win_percent from games_side where svn_release=(select max(svn_release) from games_side) group by ai_ident_me order by ai_ident_me;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
$a = "";
$b = "";
$i = true;
while($myrow = pg_fetch_assoc($result)) {
if ($i) {
$a=$a.$myrow['ai_ident_me'];
$b=$b.$myrow['win_percent'];
$i=false;
} else {
$a=$a."|".$myrow['ai_ident_me'];
$b=$b.",".$myrow['win_percent'];
}
}
printf("<img src=\"http://chart.apis.google.com/chart?cht=p3&amp;chd=t:$b&amp;chs=500x200&amp;chl=$a\" alt=\"win percentages\" title=\"win percentages\"");
?>
<h2>By AI:</h2>
<table border=1>
<tr>
<th>AI</th>
<th>SVN Release</th>
<th>Win %</th>
<th>Games</th>
<th>Wins</th>
<th>Losses</th>
<th>Avg. turns to win</th>
<th>Avg. turns to lose</th>
</tr>
<?php
$query = "select ai_ident_me, svn_release, avg_from(sum(win)*100,count(*)) as win_percent, count(*) as games, sum(win) as wins, sum(draw) as draws, sum(loss) as losses, avg_from(sum(win_turns),sum(win)) as avg_win_turns, avg_from(sum(loss_turns),sum(loss)) as avg_loss_turns from games_side group by ai_ident_me, svn_release order by ai_ident_me, svn_release desc;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
while($myrow = pg_fetch_assoc($result)) {
printf ("<tr><td>%s</td><td>%d</td><td>%.1f</td><td>%d</td><td>%d</td><td>%d</td><td>%.1f</td><td>%.1f</td></tr>",
$myrow['ai_ident_me'],$myrow['svn_release'],$myrow['win_percent'],$myrow['games'],$myrow['wins'],$myrow['losses'],$myrow['avg_win_turns'],$myrow['avg_loss_turns']);
}
?>
</table>
<h2>By AI and side</h2>
<table border=1>
<tr>
<th>AI</th>
<th>Side</th>
<th>SVN Release</th>
<th>Win %</th>
<th>Games</th>
<th>Wins</th>
<th>Losses</th>
<th>Avg. turns to win</th>
<th>Avg. turns to lose</th>
</tr>
<?php
$query = "select ai_ident_me, my_side, svn_release, avg_from(sum(win)*100,count(*)) as win_percent, count(*) as games, sum(win) as wins, sum(draw) as draws, sum(loss) as losses, avg_from(sum(win_turns),sum(win)) as avg_win_turns, avg_from(sum(loss_turns),sum(loss)) as avg_loss_turns from games_side group by ai_ident_me, my_side, svn_release order by ai_ident_me, my_side, svn_release desc;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
while($myrow = pg_fetch_assoc($result)) {
printf ("<tr><td>%s</td><td>%s</td><td>%d</td><td>%.1f</td><td>%d</td><td>%d</td><td>%d</td><td>%.1f</td><td>%.1f</td></tr>",
$myrow['ai_ident_me'],$myrow['my_side'],$myrow['svn_release'],$myrow['win_percent'],$myrow['games'],$myrow['wins'],$myrow['losses'],$myrow['avg_win_turns'],$myrow['avg_loss_turns']);
}
?>
</table>
<h2>By AI and map</h2>
<table border=1>
<tr>
<th>AI</th>
<th>Map</th>
<th>SVN Release</th>
<th>Win %</th>
<th>Games</th>
<th>Wins</th>
<th>Losses</th>
<th>Avg. turns to win</th>
<th>Avg. turns to lose</th>
</tr>
<?php
$query = "select ai_ident_me, map, svn_release, avg_from(sum(win)*100,count(*)) as win_percent, count(*) as games, sum(win) as wins, sum(draw) as draws, sum(loss) as losses, avg_from(sum(win_turns),sum(win)) as avg_win_turns, avg_from(sum(loss_turns),sum(loss)) as avg_loss_turns from games_side group by ai_ident_me, map, svn_release order by ai_ident_me, map, svn_release desc;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
while($myrow = pg_fetch_assoc($result)) {
printf ("<tr><td>%s</td><td>%s</td><td>%d</td><td>%.1f</td><td>%d</td><td>%d</td><td>%d</td><td>%.1f</td><td>%.1f</td></tr>",
$myrow['ai_ident_me'],$myrow['map'],$myrow['svn_release'],$myrow['win_percent'],$myrow['games'],$myrow['wins'],$myrow['losses'],$myrow['avg_win_turns'],$myrow['avg_loss_turns']);
}
?>
</table>
<h2>By AI and own faction</h2>
<table border=1>
<tr>
<th>AI</th>
<th>Own faction</th>
<th>SVN Release</th>
<th>Win %</th>
<th>Games</th>
<th>Wins</th>
<th>Losses</th>
<th>Avg. turns to win</th>
<th>Avg. turns to lose</th>
</tr>
<?php
$query = "select ai_ident_me, faction_me, svn_release, avg_from(sum(win)*100,count(*)) as win_percent, count(*) as games, sum(win) as wins, sum(draw) as draws, sum(loss) as losses, avg_from(sum(win_turns),sum(win)) as avg_win_turns, avg_from(sum(loss_turns),sum(loss)) as avg_loss_turns from games_side group by ai_ident_me, faction_me, svn_release order by ai_ident_me, faction_me, svn_release desc;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
while($myrow = pg_fetch_assoc($result)) {
printf ("<tr><td>%s</td><td>%s</td><td>%d</td><td>%.1f</td><td>%d</td><td>%d</td><td>%d</td><td>%.1f</td><td>%.1f</td></tr>",
$myrow['ai_ident_me'],$myrow['faction_me'],$myrow['svn_release'],$myrow['win_percent'],$myrow['games'],$myrow['wins'],$myrow['losses'],$myrow['avg_win_turns'],$myrow['avg_loss_turns']);
}
?>
</table>
<h2>By AI and enemy faction</h2>
<table border=1>
<tr>
<th>AI</th>
<th>Enemy faction</th>
<th>SVN Release</th>
<th>Win %</th>
<th>Games</th>
<th>Wins</th>
<th>Losses</th>
<th>Avg. turns to win</th>
<th>Avg. turns to lose</th>
</tr>
<?php
$query = "select ai_ident_me, faction_enemy, svn_release, avg_from(sum(win)*100,count(*)) as win_percent, count(*) as games, sum(win) as wins, sum(draw) as draws, sum(loss) as losses, avg_from(sum(win_turns),sum(win)) as avg_win_turns, avg_from(sum(loss_turns),sum(loss)) as avg_loss_turns from games_side group by ai_ident_me, faction_enemy, svn_release order by ai_ident_me, faction_enemy, svn_release desc;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
while($myrow = pg_fetch_assoc($result)) {
printf ("<tr><td>%s</td><td>%s</td><td>%d</td><td>%.1f</td><td>%d</td><td>%d</td><td>%d</td><td>%.1f</td><td>%.1f</td></tr>",
$myrow['ai_ident_me'],$myrow['faction_enemy'],$myrow['svn_release'],$myrow['win_percent'],$myrow['games'],$myrow['wins'],$myrow['losses'],$myrow['avg_win_turns'],$myrow['avg_loss_turns']);
}
?>
</table>
<h2>By AI and factions</h2>
<table border=1>
<tr>
<th>AI</th>
<th>Own faction</th>
<th>Enemy faction</th>
<th>SVN Release</th>
<th>Win %</th>
<th>Games</th>
<th>Wins</th>
<th>Losses</th>
<th>Avg. turns to win</th>
<th>Avg. turns to lose</th>
</tr>
<?php
$query = "select ai_ident_me, faction_me, faction_enemy, svn_release, avg_from(sum(win)*100,count(*)) as win_percent, count(*) as games, sum(win) as wins, sum(draw) as draws, sum(loss) as losses, avg_from(sum(win_turns),sum(win)) as avg_win_turns, avg_from(sum(loss_turns),sum(loss)) as avg_loss_turns from games_side group by ai_ident_me, faction_me, faction_enemy ,svn_release order by ai_ident_me, faction_me, faction_enemy, svn_release desc;";
$result = pg_query($query);
if (!$result) {
echo pg_last_error();
exit();
}
while($myrow = pg_fetch_assoc($result)) {
printf ("<tr><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%.1f</td><td>%d</td><td>%d</td><td>%d</td><td>%.1f</td><td>%.1f</td></tr>",
$myrow['ai_ident_me'],$myrow['faction_me'],$myrow['faction_enemy'],$myrow['svn_release'],$myrow['win_percent'],$myrow['games'],$myrow['wins'],$myrow['losses'],$myrow['avg_win_turns'],$myrow['avg_loss_turns']);
}
?>
</table>
</body>