Archive

Posts Tagged ‘Python’

Insulae – automatisiertes Veroeffentlichen in Sozialen Netzwerken

May 30th, 2010 Jan H. Krueger No comments

Um alle Interessenten stets schnell und einfach ueber Neuerungen in Insulae informieren zu koennen, habe ich ein wenig rumprobiert und nun die erste Version der Netzwerkanbindung fuer Insulae fertig gestellt.
Konkret: mittels eines neu erstellten Formulares koennen Ankuendigung und News bequem zentral erfasst werden. Daraufhin wird die Ankuendigung aktuell an fuenf Orte eingestellt:

  • News-Seite in Insulae
  • Insulae-Forum
  • dieses Blog
  • Twitter
  • Google Buzz

Als naechsten Schritt werde ich versuchen mich mit der API zu Facebook auseinander zu setzen um auch hier einen direkten Zugang per Skript zu erlangen. Infoquellen per RSS-Feeds ergeben sich aus den genannten Quellen ebenfalls.

Dabei ist die Anbindung an die eigene News-Seite und ins Forum trivial, da Eigenentwicklungen. Daher werde ich hier auch nicht weiter darauf eingehen.

Die Twitter-API ist dankenswerterweise simpel wie es nur sein kann.

#!/usr/bin/python
 
import os
import twitter
 
E = sys.exit
 
##############################
# Send message to Twitter
##############################
 
try:
    # API initialisieren
    client = twitter.Api()
 
    # Authentifizieren
    client = twitter.Api(username='twitterusername', password='twitterpassword')
 
    # Nachricht an Twitter senden
    update = client.PostUpdate(message)
except: 
    print ("Keine Anbindung an Twitter moeglich.") 
    E(8)

Schwupps, Text bei Twitter gepostet.

Fuer Google Buzz sieht es etwas schwieriger aus. Ich habe noch keine ueberzeugende API dafuer gefunden. Doch Google hat die Moeglichkeit geschaffen, auch mittels einer E-Mail an Buzz zu senden. Daher ist die Hauptaufgabe fuer Buzz eigentlich der Versand einer E-Mail.

#!/usr/bin/python
 
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email import Encoders
import os, getopt, sys
 
# Hier die zu veroeffentlichende Nachricht
message = "Beispielnachricht"
 
# Google Buzz Konfiguration
gmail_user = "username@googlemail.com"
gmail_pwd  = "password"
 
# Ab hier nichts mehr veraendern
 
# Derzeit verarbeitet Google Buzz lediglich den Titel einer
# eingehenden Mail. Daher muss die Nachricht direkt in den
# Mailtitel geschrieben werden.
# so subject = message
subject = message
 
E = sys.exit
 
##############################
# Send message to Google Buzz
##############################
try:
    msg = MIMEMultipart()
    msg['From']    = gmail_user
    msg['To']      = "buzz@gmail.com"
    msg['Subject'] = subject
    msg.attach(MIMEText(message))
 
    smptServer = smtplib.SMTP("smtp.gmail.com", 587)
    smptServer.ehlo()
    smptServer.starttls()
    smptServer.ehlo()
    smptServer.login(gmail_user, gmail_pwd)
    smptServer.sendmail(gmail_user, to, msg.as_string())
    smptServer.close()
except: 
    print ("Kein Versand an Google Buzz moeglich") 
    E(8)

Grosser Dank fuer diesen Teil geht dabei an samof76 von Megam: Cloud Buzz. Dort habe ich die Basis fuer den Mailversand her.

Der Einfachheit halber habe ich hier in den Beispielen zwei separate Skripte vorgestellt. Fuer Insulae sind die entsprechenden Schritte im Portal zentral eingebettet.

Warum der Aufwand? Um schnell und einfach in verschiedenen Kanaelen Informationen ueber Insulae zu verbreiten. In meinen Augen ist es in der heutigen Zeit notwendig, die zur Verfuegung stehen Mittel auch vollstaendig zu nutzen. Je breiter die Informationsbasis, umso mehr potentielle Spieler lassen sich finden. Je mehr Informationskanaele genutzt werden, umso geringer die Wahrscheinlichkeit einen potentiellen Spieler nicht zu erreichen. Daher gilt ein meinen Augen: Der Spieler sucht sich den Informationskanal, der ihm gefaellt. Gerade Browsergames bei denen keine grosse Entwicklungsfirma im Hintergrund steht, koennen sich in meinen Augen nicht erlauben, Spielern zu diktieren welchen Kanal sie zu nutzen haben, erst recht wenn sie erst noch Spieler werden sollen. Gar nichts zu veroeffentlichen ist inakzeptabel.

Wenn wie oben bereits angesprochen auch Facebook in mein Portal integriert ist, habe ich denke ich eine gute bis sehr gute Abdeckung von Informationskanaelen die ich mit Infos bestuecke. Dabei gilt: je mehr, umso besser. Aber nur relevante Informationen! Zu wenig, und Spieler koennen den Eindruck gewinnen das ein Projekt eingeschlafen ist. Zu viele, und wichtige Infos koennen unter der Masse verloren gehen.

Daher: Spread the word!

Interessant waere es eventuell auch, Google Wave anzusprechen. Doch derzeit bin ich vom insgesamten Nutzen von Wave nicht ueberzeugt, daher steht dieses Kanal auch noch sehr weit hinten an. Ob, ausser Facebook und eventuelle Google Wave, noch andere Kanaele angebunden werden… das kann ich zum aktuellen Zeitpunkt noch nicht sagen. Ich wuensche mir allerdings, das die verbliebenen deutschen Browsergame-Portale entsprechende Schnittstellen anbieten wuerden damit auch diese in einem Schritt gefuettern werden koennen. Aber dies wird wohl niemals passieren.

Nebenbei: die Suchmaschinen werden mittels Ping-Dienste aus dem Blog bereits darauf hingewiesen das es neues futter fuer sie gibt welches sie konsumieren koennen. Also auch dieser Teil erfolgreich abgedeckt.

Insulae – Parlez-vous … was anderes?

July 14th, 2009 Jan H. Krueger No comments

In den letzten Wochen war es etwas still um Insulae. Das liegt mitnichten daran das ich nichts getan habe, sondern eher daran das ich viel mehr Hintergrundarbeiten erledigt habe. Ein großer Teil davon ist die Lokalisierung.

Konkret bin ich an drei “Meilensteinen” dran:

  • Umstellung von Insulae auf Python mittels Django als Web-Framework
  • Entwicklung eines reinen Admin- und Moderatorenpanels zur Spielsteuerung
  • Nutzung der von Django bereitgestellten Mittel um gemäß i18N zu arbeiten

Also doch schon drei große Teile. Im Adminpanel ich ich derzeit am weitesten, wobei die Entwicklung hierbei Hand in Hand mit dem driten Punkt geht. Ist auch eine gute Übung bevor ich das ganze mit dem eigentlichen Spiel vorrantreibe. Die Anpassungen an die Django-Templates sind hierbei auch sehr einfach zu sehen. Zu Beginn eines Templates muss Django mitgeteilt werden das für dieses Template eine Übersetzung versucht werden soll. Schnell getan mittels folgendem Zusatz welcher in die erste Zeile kommt:

{% load i18n %}

Nun ja, und danach ist eigentlich alles genauso einfach. An jede Stelle an die ich bisher einen festen String mit einem Wort eingegeben habe, ersetze ich eine bestimmte Codezeile im Template. Will ich zum Beispiel das der auf deutsch benannte Link “Eigene Nachrichten” je nach unterstützter Sprache übersetzt wird, teile ich dies dem Template wie folgt mit

{% trans "Eigene Nachrichten" %}

Das kann ich direkt während der Erstellung eines neuen Templates angeben. So sehe ich in dieser Phase was ich an dieser Stelle bezwecken will, ohne weitere Anpassungen.

Schön und gut, aber wie kann ich nun dafür sorgen das die Zeichenkette “Eigene Nachrichten” für einen englischsprachigen Benutzer eben in Englisch angezeigt wird? Zu erst muss eine Liste mit den zu übersetzenden Texten erstellt werden. Dazu ist ein klein wenig Vorarbeit zu leisten. Im Verzeichnis meines Django-Projelktes, Insulae, habe ich einen weiteren Ordner mit dem Namen “locale” angelegt. Dies muss manuell getan werden. Die Verzeichnisstruktur sieht dann also wie folgt aus, nun nachdem ich den Ordner angelegt habe:

Verzeichnisstruktur Djangp-Projekt
Wobei das nur die Struktur auf meinem Ausweichrechner ist.

Nachdem das Verzeichnis angelegt ist, kann Django angewiesen werden alle Quelldateien zu durchsuchen und alle wie oben gekennzeichneten Strings auszugeben. Beim Aufruf von django-admin.py sind noch ein paar Parameter zu beachten. Der wichtigste ist sicherlich makemessages, welcher Django anweist überhaupt die Liste zu erzeugen. Weiterhin noch die Sprache für die die Übersetzung angelegt werden soll. Dies geschieht mittels -l [Ländercode]. Dann kann noch optional mittels des Parameters -e angegeben werden, dass nicht nur die üblichen Quelldateien analysiert werden sollen, sondern eben alle mit den angegebenen Endungen. Der Parameter -a gibt an, das ich eine bereits bestehende Liste aktualiseren will, und nicht immer wieder eine leere. Für mich sieht nun konkret der Aufruf wie folgt aus:

django-admin.py makemessages -l de -e phtml -a

bzw. für eine englische Sprachversion:

django-admin.py makemessages -l en -e phtml -a

Daraufhin entstehen neue Unterverzeichnisse in locales. Bei mir konkret habe ich dann $PROJECTPATH/locale/de/LC_MESSAGES/ Dort liegt nun eine Datei namens django.po bzw. auch für englisch ein entsprechender en-Unterordner. Diese .po-Datei ist im Grunde nur eine Textdatei in der alle Strings welche ich für eine Übersetzung vorgesehen habe enthalten sind in folgendem Format:

Deutsch:

#: .\templates\spieler.phtml.py:112
#, fuzzy
msgid "Accountdaten bearbeiten"
msgstr ""

msgid gibt den zu übersetzenden String an, msgstr den Zielstring. Wird dieser leer gelassen, wird einfach msgid ausgegeben. So brauche ich keine doppelten Nennungen vorhalten. In der .po-Datei für die englischen Seiten trage ich nun die Übersetzung ein und erhalte folgendes:
Englisch:

#: .\templates\spieler.phtml.py:112
#, fuzzy
msgid "Accountdaten bearbeiten"
msgstr "Edit Account"

Nun ist diese Vorlage noch umzusetzen. Dies wird wieder von django-admin erledigt, bis auf den ersten Parameter sind keine weiteren notwendig. Es werden grundsätzlich alle Sprachen die wie oben angelegt wurden verarbeitet.
django-admin.py compilemessages
Dies erzeugt nun in zusätzlich zu den .po-Dateien Dateien mit der Endung .mo. Nun ja, das wars. Da meine Browser hier persönlich immer deutsch, also deDE als Locale liefern, ich aber ggf. eine englische Übersetzung auch testen will, kann dies in der settings.py des Django-Projectes auch eingestellt werden. Dort trage ich ind er Regel LANGUAGE_CODE = 'de-DE' ein. Will ich jedoch die englischen Texte lesen, ändere ich dies einfach auf LANGUAGE_CODE = 'en-EN'. Fertig.

Das ist nun alles was als Basis notwendig ist. Wenn eine neue Sprache eingepflegt werden soll, kann einfach eine neue wie oben beschrieben angelegt werden und einem übersetzungswilligen Spieler / Mitarbeiter gegeben werden. Wenn diese zurückkommt, einfach mittels compilemessages bearbeiten und schon steht eine neue Sprache zur Verfügung.

Ok, war jetzt mehr ein Ausflug wie in Django i18N genutzt wird. Macht aber nichts. Für alle die Fragen, in Insulae tut soch noch was, aber eben eher im Hintergrund. Einzig eine Sache wird schon partiell genutzt. Ich habe die Datenbankgrundlagen für ein System mit mehreren Postfächern gelegt. Jeder Spieler kann prinzipiell mehrere Postkörbe zugewiesen bekommen. Dies ist erst einmal der persönliche wie er auch aus Scherbenwelten bekannt ist. Gleichzeitig bekommt auch jede Stadt einen Postkorb. Zum einen werden so die Nachrichten von Spieler und Stadt ordentlicher voneinander getrennt, gleichzeitig gehen somit auch die Nachrichten einer Stadt bei einem Besitzerwechel mit. Ich kann nun spezielle Admin- bzw. Support-Postkörbe einrichten welche der Support bzw. ich als Admin lesen und bearbeiten können ohne einen besonderten LogIn zu nutzen. Weitergehend, ein solcher Postkorb ist nun streng genommen nicht mehr Spiel-gebunden sondern kann auch über andere Dienste gefüllt werden.

Python-Umstellung erfolgreich

June 30th, 2009 Jan H. Krueger No comments

Soeben habe ich die Weichen stellen koennen um meine bisherigen Python-Skripte “zukunftssicher” zu gestalten.
Bisher habe ich noch mit Python 2.5 gearbeitet, doch so langsam machte sich dann doch die Umstellungslust breit. Also die heute frisch erschienene Version 3.1 gezogen und installiert. Da kam dann gleich die erste Frage auf, “Wie schauts mit der PostGres-Anbindung aus?” Im Netz geschaut, aber von Psycopg2 gibt es keine Version fuer Python 3. Schade. Aber sehr schnell habe ich pg8000 gefunden. Erfreulicherweise kam hier kaum eine Aenderung im Quellcode meiner bisherigen Arbeiten auf mich zu. Die Import-Anweisungen habe ich ausgetauscht und danach noch die Connect-Anweisung. Der komplette Rest, Querys, Result-Verarbeitung… alles geblieben wie unter Psycopg2. Sehr fein. Wenn das auch in anderen Sprachen so einfach waere.

Ein weiterer grober Check ueber meine anderen Module.. passt alles. Auch die Datumsfunktionen arbeiten noch wie gewuenscht, also derzeit noch keine wichtigen Verluste.

Was derzeit noch nich verfuegbar ist, ist eine aktuelle Version von Django. Aber an dieser Stelle habe ich noch etwas Zeit. Bis die Insulae-Klassen alle von PHP nach Python portiert wurden werde ich sowieso noch keine Zeit haben ich wieder um die Oberflaeche zu kuemmern. Und irgendwie ist Zeit derzeit so extrem fluechtig. Und bis ich dann tatsaechlich wieder daran komme mit matplotlib zu arbeiten, das dauert.

Categories: Insulae Tags: , , , ,

Bots fuer Browsergames mittels Python

January 28th, 2009 Jan H. Krueger No comments

Eher durch Zufall bin ich die Tage auf ein Pythonpaket aufmerksam geworden, welches sich als enorm maechtig erwiesen hat. Das Paket Mechanize gibt sich wenn es Webseiten einliest, dabei also Browser aus. Ja, es verwaltet die Cookies sogar selbststaendig. Was ist die Konsequenz daraus? Es ist damit sehr leicht moeglich sich in Browsergames einzuloggen und direkt Automatismen zu realisieren.

Gesagt getan, ein wenig rumprobiert und ich konnte mich mit einem kurzen Testskript in Insulae einloggen und meine aktuellen AP auslesen. Doch, Insulae ist ja “nur” ein Klon von Scherbenwelten. Ob ich damit auch in Scherbenwelten agieren konnte? Zugegeben, es war spaet und meine Neugier geweckt. Also habe ich dies einmal ausprobiert und siehe da, auch in Scherbenwelten konnte ich mich ohne Widerstand einloggen und meine AP auslesen. Ich muss sagen, ich war schockiert wie einfach es doch moeglich ist. Schlimmer noch. In Spielen wie Insulae und Scherbenwelten findet die Steuerung ueber Links und Formulare statt. Und genau dies, das bestuecken von Formularen und Absenden eben dieser wird bereits mit der Anmeldung erledigt. Konkret sind ein nur ein paar Befehle relevant um Daten aus einem Spiel auszulesen und dann zu verwerten.

br.open("http://www.example.de/example.php")

Macht nichts anderes wie eine Webseite zu oeffnen bzw. zu laden. Mechanize verarbeitet es automatisch wenn der Webserver direkt auf eine andere Seite weiterleitet.

br.select_form(nr=0) 
br['FORMFELD1']=(usern) 
br['FORMFELD2']=(passw) 
response2=br.submit()

Traegt in ein Formular, in diesem Beispiel das erste Formular auf der Webseite, in die angegebenen Felder FORMFELD1 und FORMFELD2 die Werte aus usern und passw ein. Und dann wird mittels der Methode submit() das ganze abgeschickt und das Ergebnis in response2 geladen. Absolut simpel. Allerdings auch etwas Quick and Dirty, denn sobald sich an der Reihenfolge der Formulare aendert waere hier ein Anpassung notwendig. Dafuer kann man allerdings die gelesene Seite parsen und sich dann den Index des gewuenschten Formulaeres ermitteln. Kann, aber fuer den einfachen Funktionstest reicht es.

htmlinhalt = response.read()

Damit laesst sich eine Webseite komplett einlesen. Wihlgemerkt, der Quellcode einer Webseite. Seite, nicht Site. Welche dies ist, das hat man vorher mit dem oben bereits gezeigten br.open() angegeben. Das ist ideal wenn ich dann anschliessend htmlinhalt mittels Regular Expressions auswerte.

print br.geturl()

Dieser kleine Aufruf kann recht hilfreich sein um zu ermitteln, auf welcher Seite das Programm sich gerade befindet. Gerade wenn bekannt ist das es Weiterleitungen gibt kann ich hiermit pruefen ob ich noch auf der erwarteten Seite bin oder anders reagieren muss.

Alles in allem kein Hexenwert, aber dennoch die Grundelemente um Spiele wie Insulae oder Scherbenwelten mittels eines Bots zu automatisieren. Gerade die Behandlung der Formulare ist sehr komfortabel.

Ich habe gestern die Spielleitung von Scherbenwelten darauf hingewiesen das es eben eine solche Schwäche gibt. Bisher jedoch ohne Antwort. Mal schauen wann da was kommt.

Unterdessen probierte ich ein wenig in Insulae rum wie ich dort einen solchen Bot blockieren kann. Erster Ansatz: Captchas. Widerlich und nervig. Und leider erfolglos. Die simplen Captcas welche einen Text darstellen der in ein Formular eingegeben werden muss sind mittels des Pythonpaketes pytessa auszuhebeln. Pytessa nutzt das Programm Tesseract um eben den Text aus Bildern zu extrahieren. Verwandt mit OCRad. Fuer die fiesen DInger, die Bilder mit den Kreisen in bei denen in den nicht geschlossenen Kreis geklikt werden muss, dafuer gibt es cdetect. Habe dies gestern kennengelernt als jemand einen Manager (Bot) fuer Pennergame schreiben wollte und dann eben an diese Captchas gelangt ist. Fazit: Captchas doof. Aergern nach aktuellem Stand der Technik nur die menschlichen Benutzer und sind fuer Bots bzw. deren Entwickler lediglich einmaliger Mehraufwand.

Eine intensive Nutzung von Ajax, also JavaScript, scheint soetwas zu erschweren, aber keine dauerhafte Huerde zu sein. Faellt also auch weg. Scheint fast nur noch Flash ueber zu bleiben. Und da habe ich mal dezent meine Vorbehalte gegen.

Keine wirkliche Loesung, aber zeitweise eine Blockade waere die Formularnamen zu veraendern. Ist aber auch doof. Oder gibt es einen Weg Forumulardaten benutzerbezogen zu gestalten? Bestimmt, aber das wuerde erst dann greiffen nachdem sich ein Benutzer bereits angemeldet hat. Die Erkennung eines solchen Bots laesst sich auch noch elegent erschweren. Da sich mechanize also Browser ausgibt, kann ich ihm auch mitgeben als welcher Browser es sich ausgibt.

br.addheaders = [ ("User-agent", "Mozilla/5.0 (compatible)") ]

Simpel und auf der Seite des Webservers somit nicht mehr zu erkennen. Schoene Scheisse.

Aber um mal wieder auf ein Thema von vorhin zurueck zu kommen: Alles ist komplett frei und fuer jeden verfuegbar. Auch die Texterkennung von den Captchas, direkt per Google zu finden. Ein solches Pythonprogramm welches die AP in Scherbenwelten ausliest war in 20 Minunten geschrieben. Wer also wirklich vor hat einen Bot zu schreiben, der findet die besten Vorraussetzungen in Python, ist bereits alles da und muss nur genutzt werden.
Lediglich die Dokumentation von mechanize ist etwas duerftig, aber Versuch und Fehler, nach ein paar Iterationen hat man sich durchgehangelt.

Verwendete Software:
Python 2.5, Stackless
Mechanize 0.1.10

Das wars. Am laengsten hat es gedauert das ganze zum Laufen zu bringen, da unter Windows Vista bei mir mechanize nicht sauber seine Abhaengigkeit, ClientForm, mit installierte. Aber nach einer manuellen Nachinstallation lief es dann.

Quelle: Mechanize, Scherbenwelten

Statistikermittlung fuer Insulae

January 22nd, 2009 Jan H. Krueger No comments

Und wieder ein weiteres Skript in ein Pythonprogramm umgewandelt. Dieses mal ist es ein Skript gewesen welches fuer mich ein paar Zahlen und Daten aus Insulae ermittelt und ablegt. Zum Beispiel wieviele Spieler sich gerade in einer bestimmten Region aufhalten.
Anhand dieser Daten kann ich dann gegebenenfalls in Insulae eingreiffen und Aktionen starten. Denn wenn ich feststelle das sich auf einmal die Mehrheit der Spieler an einem Fleck sammelt und sich nicht ueber die Welt verteilen, dann kann ich entsprechend reagieren. Oder sollte ich feststellen das 90% aller Spieler einem einzigen Gott huldigen, dann sollte ich mal dringen ueberpruefen ob die durch den Gott gewaehrten Boni nicht eventuell zu stark sind. Ums kurz zu machen, diese Auswertungen stellen fuer mich ein mittel der Spielsteuerung dar.

Wie auch immer. Die Grundlage ist nun geschaffen, damit ist der Weg frei in der Zukunft weitere Auswertungen zu implementieren.

Und wenn ich noch ein paar Tests mit der PIL gemacht habe, dann kann ich die gesammelten Daten den Moderatoren auch direkt grafisch zur Verfuegung stellen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#! /usr/local/bin/python
##
# Copyright (c) 2009, Jan H. Krueger
# All rights reserved.
#
# The contents of this file are subject to the GNU Lesser General Public
# License (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.gnu.org/licenses/lgpl.html
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
#
#
# File: ermittle_statistiken.py
# Authors: Jan H. Krueger (game.insulae@googlemail.com)
# Created: (04/09/2003)
# Last Updated: (21/01/2009)
# Version: 1.0
# Package: Insulae
# Category: Insulae-Backend
#
# History:
# 11/02/2006    Umstellung auf dbx
# 25/05/2006    Umstellung auf neue Historie-Art
# 19/06/2006    Kontrolle und Wiedereinsetzung in die Cronjobs
# 18/01/2009    Umstellung auf Python
# 21/01/2009    Wiedereinbau der Statistiken fuer Spielerregionen, Haeuser
#
 
#
# collects some statistics and numbers of the game
#
 
import psycopg2
import psycopg2.extensions
import conn as db
import sys
import time
 
E = sys.exit
 
### Connect to the postgresql database and open a cursor
con = psycopg2.connect(
    database = db.dbdatabase,
    host = db.dbhost,
    user = db.dbuser,
    password = db.dbpassword
    )
cu=con.cursor()
 
skriptname = 'ermittle_statistiken.py'
 
# log the start of ermittle_statistiken.py
try:
    varstatus = 'beginn'
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """insert into daten.skriptlog (skriptname, zeitstempel, 
             verarbeitungsstatus) values (%s, %s, %s)
          """
    cu.execute(sql, (skriptname, vartime, varstatus))
    con.commit()
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
zeit = time.mktime(time.localtime(time.time()))
vartime = str(zeit)[0:-2]
 
# selects the skills
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT min(fertigkeit_stufe) as minimum, avg(fertigkeit_stufe) as 
          durchschnitt, max(fertigkeit_stufe) as maximum, fertigkeit_id FROM 
          spieler.charakter_fertigkeit GROUP BY fertigkeit_id 
          ORDER BY fertigkeit_id
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (minimum, durchschnitt, maximum, fertigkeit_id) in statdaten:    
        sql = """
              INSERT INTO daten.fertigkeit (df_fertigkeit, df_datum, 
              df_minimum, df_durchschnitt, df_maximum) 
              VALUES (%s, %s, %s, %s, %s)
              """
        cu.execute(sql, ( fertigkeit_id, vartime, minimum, durchschnitt, 
                          maximum) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
# selects the classes
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT Count(charakter_beruf) as anzahl, charakter_beruf, 
          charakter_hauptcharakter FROM spieler.charakter 
          GROUP BY charakter_beruf, charakter_hauptcharakter
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (anzahl, charakter_beruf, charakter_hauptcharakter) in statdaten:    
        sql = """
              INSERT INTO daten.beruf (berufsdaten_beruf, berufsdaten_datum, 
              berufsdaten_anzahl, berufsdaten_hauptcharakter) 
              VALUES (%s, %s, %s, %s)
              """
        cu.execute(sql, ( charakter_beruf, vartime, anzahl, 
                          charakter_hauptcharakter) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
# selects the races
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT Count(charakter_volk) as anzahl, charakter_volk, 
          charakter_hauptcharakter FROM spieler.charakter 
          GROUP BY charakter_volk, charakter_hauptcharakter 
          ORDER BY charakter_volk
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (anzahl, charakter_volk, charakter_hauptcharakter) in statdaten:    
        sql = """
              INSERT INTO daten.volk (dv_volk, dv_datum, dv_anzahl, 
              dv_hauptcharakter) VALUES (%s, %s, %s, %s)
              """
        cu.execute(sql, ( charakter_volk, vartime, anzahl, 
                          charakter_hauptcharakter) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
# selects the deities
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT Count(charakter_gott) as anzahl, charakter_gott, 
          charakter_hauptcharakter FROM spieler.charakter 
          GROUP BY charakter_gott, charakter_hauptcharakter 
          ORDER BY charakter_gott
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (anzahl, charakter_gott, charakter_hauptcharakter) in statdaten:    
        sql = """
              INSERT INTO daten.glaube (dg_gott, dg_datum, dg_anzahl, 
              dg_hauptcharakter) VALUES (%s, %s, %s, %s)
              """
        cu.execute(sql, ( charakter_gott, vartime, anzahl, 
                          charakter_hauptcharakter) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
### selects how many players are in a specific region
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT Count( spieler.spieler_id ) AS anzahl, 
          COALESCE ( welt.karte.karte_id, 999 ) AS Region 
          FROM spieler.spieler LEFT JOIN welt.karte ON (
          welt.karte.karte_x = spieler.spieler_x 
          AND welt.karte.karte_y = spieler.spieler_y 
          AND welt.karte.karte_w = spieler.spieler_w ) 
          WHERE spieler.spieler_verwaltung = 'n' 
          GROUP BY welt.karte.karte_id
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (anzahl, region) in statdaten:    
        sql = """
              INSERT INTO daten.region (dr_region, dr_datum, dr_anzahl) 
              VALUES (%s, %s, %s)
              """
        cu.execute(sql, ( region, vartime, anzahl) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
### collects how many people lives in the towns, only min, max, avg
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT min( stadt_einwohner ) as min, avg( stadt_einwohner ) as avg, 
          max( stadt_einwohner ) as max FROM stadt.stadt
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (min, avg, max) in statdaten:    
        sql = """
              INSERT INTO daten.stadteinwohner (ds_datum, ds_minimum, 
              ds_durchschnitt, ds_maximum) VALUES (%s, %s, %s, %s)
              """
        cu.execute(sql, ( vartime, min, avg, max) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
 
# selects how many buildings are build
try:
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """
          SELECT Count( h.wh_haustyp ) as anzahl, h.wh_haustyp as haustyp
          FROM welt.haus h, spieler.spieler s 
          WHERE h.wh_spieler = s.spieler_id AND s.spieler_verwaltung = 'n' 
          GROUP BY h.wh_haustyp
          """
    cu.execute(sql)
    statdaten = cu.fetchall()
 
    for (anzahl, haustyp) in statdaten:    
        sql = """
              INSERT INTO daten.haus (dh_haus, dh_datum, dh_anzahl) 
              VALUES (%s, %s, %s)
              """
        cu.execute(sql, ( haustyp, vartime, anzahl) )
        con.commit()
 
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
 
# Log the ending of ermittle_statistiken.py.
try:
    varstatus = 'ende'
    zeit = time.mktime(time.localtime(time.time()))
    vartime = str(zeit)[0:-2]
    sql = """insert into daten.skriptlog (skriptname, zeitstempel, 
             verarbeitungsstatus) values (%s, %s, %s)"""
    cu.execute(sql, (skriptname, vartime, varstatus)) 
    con.commit()
except psycopg2.ProgrammingError, errval: 
    print errval 
    E(8)
 
 
# Close the cursor and connection, end the script.
cu.close() 
con.close()
E(0)