[software_challenge] v0002

  • From: nebu <nebu@xxxxxxxxx>
  • To: software_challenge@xxxxxxxxxxxxx
  • Date: Thu, 17 Jan 2008 17:02:17 +0100

Hallo,

ich habe Version v0002 beigeheftet. Inzwischen kann der Client recht rudimentär spielen und mir ist es schon einige Male gelungen, ein Spiel komplett durchzuspielen.
Ein paar Bugs sind immernoch drin. Nagut - eine ganze Menge :)
Funktionalität fehlt auch noch so manches. Aber darum will ich mich in der nächsten Zeit kümmern um zumindest einen möglichst fehlerfreien und vollständigen Client zu haben, sodass ich dann eine rudimentäre Strategie implementieren kann.

Ich bin da ganz zuversichtlich.

Zum Programm selbst; der Code ist - für meinen Geschmack - leicht zu lesen und erweiterbar. Dank Python. Von der Performance ist er bisher auch gar nicht mal schlecht.

Ach, und der Client heißt jetzt Ajax.

Gruß,
   Jan
# -*- coding: utf-8 -*-

import socket
import os
import string
import numpy
import random
import sys

log_datei = "client_log.txt"

spieler_nummer = 0

spieler_steine = []

# das spielfeld
spielfeld = numpy.arange(121)
spielfeld.shape = (11,11)

# eine Liste, die wiederum zwei Listen enthält.
punktestand1 = []
punktestand2 = []

port = 10500

class Logger:
        """ Dient der Speicherung von Logdateien """
        def __init__(self, datei):
                self.datei = open(datei, 'w')
                
        def eintrag(self, meldung):
                self.datei.write(meldung+"\n")
                self.datei.flush()
                os.fsync(self.datei)

class Netzwerk:
        """ Stellt Funktionen zum Verbinden,
        Senden, Empfangen und SchlieÃ?en
        von Verbindungen bereit """
        def __init__(self, port):
                self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        
        def verbinden(self):
                self.s.connect(("localhost", port))
                
        def beenden(self):
                self.s.close()
                
        def zug(self):
                self.nachricht = self.s.recv(4096)
                if self.nachricht != 0:
                        self.liste_serverstrings = string.split(self.nachricht, 
"\n")
                        self.liste_serverstrings.pop( 
len(self.liste_serverstrings)-1)
                        self.liste_instanzen = 
self.messagehandler(self.liste_serverstrings)
                        return self.liste_instanzen
                else:
                        pass
                        
        def senden(self, nachricht):
                print "Gesendet: " + nachricht
                self.s.send(nachricht)
                        
        def messagehandler(self, serverstrings):
                """ Nimmt einen Serverstring an und gibt eine Instanz zurück 
                
                Diese Methode nimmt den Serverstring an
                und ermittelt anhand der ersten Ziffer eine
                passende Klasse. Dieser wird dann die Servernachricht
                übermittelt und die entstehende Instanz
                wird an Netzwerk zurückgegeben """
                
                self.liste_instanzen = []
                for nachricht in serverstrings:
                        if nachricht[0] == "0":
                                # Server wurde gestartet
                                #print "0: " + nachricht
                                self.liste_instanzen.append( 
SpielInit(nachricht) )
                        elif nachricht[0] == "1":
                                # Steine vom Server erhalten
                                #print "1: " + nachricht
                                self.liste_instanzen.append( Steine(nachricht) )
                        elif nachricht[0] == "2":
                                #print "2: " + nachricht
                                # Brett vom Server erhalten
                                self.liste_instanzen.append( Brett(nachricht) )
                        elif nachricht[0] == "3":
                                # Zug wird angefordert
                                #print "3: " + nachricht
                                self.liste_instanzen.append( Zug(nachricht) )
                        elif self.nachricht[0] == "4":
                                # neuen Spielstand erhalten
                                self.liste_instanzen.append( 
Spielstand(nachricht) )
                        elif self.nachricht[0] == "5":
                                # neue Informationen zu den Steinen erhalten
                                pass
                        elif self.nachricht[0] == "6":
                                # Frage, ob die Steine gewechselt werden sollen
                                print "6"
                        elif self.nachricht[0] == "7":
                                # wird nicht benutzt
                                pass
                        elif self.nachricht[0] == "8":
                                # Server-Neustart
                                spiel_laufend = False
                                log.eintrag("Server wurde neugestartet")
                        elif self.nachricht[0] == "9":
                                # Server runtergefahren
                                netzwerk.beenden()
                                log.eintrag("Server wurde beendet")
                                exit()
                return self.liste_instanzen
                        
class SpielInit:
        """ Wird einmalig zu Beginn des Spiels aufgerufen
        
        Wertet nur den ersten String
        auf die eigene Spielernumme aus """
        def __init__(self, nachricht):
                self.n = nachricht
        
        def handle_message(self):
                spieler_nummer = self.n[3]
                log.eintrag("Spiel wurde initialisiert\n\t*Spielernummer 
erhalten")
                
# Für die Steine auf der Hand verantwortlich
class Steine:
        def __init__(self, nachricht):
                self.nachricht = nachricht
                log.eintrag('Steine erhalten: ' + self.nachricht)
                self.temp_liste = [int(x) for x in self.nachricht[4:].split()]
        
        def handle_message(self):
                if self.nachricht[2] == '6':
                        self.neue_hand()
                elif self.nachricht[2] == '1':
                        self.update()
                
        def neue_hand(self):
                global spieler_steine
                spieler_steine = []
                for x in range(6):
                        stein = self.temp_liste.pop(0), self.temp_liste.pop(0)
                        spieler_steine.append(stein)
                log.eintrag("Steine eingelesen: " + str(spieler_steine) )
                        
        def update(self):
                stein = self.temp_liste[0], self.temp_liste[1]
                global spieler_steine
                spieler_steine.append(stein)                            
                
# Aktualisiert das Brett
class Brett:
        def __init__(self, nachricht):
                self.n = nachricht
                
        def handle_message(self):
                log.eintrag("Neues Brett erhalten")
                
                liste = [int(x) for x in self.n.split()]
                
                global spielfeld
                spielfeld = numpy.array(liste[1:])
                spielfeld.shape = (11,11)
                log.eintrag("Brett: " + '\t' + str(spielfeld ) )
                
# Aktualisiert und pflegt die Spielstände
class Spielstand:
        def __init__(self, nachricht):
                self.nachricht = nachricht[:4]
                
        def handle_message(self):
                log.eintrag("Neuen Spielstand erhalten: " + self.nachricht)
                temp_liste = []
                for ziffer in self.nachricht:
                        if ziffer != ' ':
                                temp_liste.append(ziffer)
                punktestand1 = temp_liste
                log.eintrag('Punktestand: ' + str( punktestand1) )
                
class Zug:
        """Zug-Klasse
        Die Zug-Klasse wird bei Nachrichten die mit '3' beginnen
        aufgerufen und enthält die zentralen Spielmechanismen
        """
        def __init__(self, nachricht):
                self.nachricht = nachricht
        
        def handle_message(self):
                if self.nachricht[2] == '0':
                        self.erster_zug()
                else:
                        self.auswertung()
                        self.ziehen()
                
        def auswertung(self):
                """Auswertung des Anhangs
                mit der Zug-Aufforderung erhält man
                auch die vorangegangen Züge des Gegners
                jene sollen an dieser Stelle ausgewertet werden.
                """
                gegnerischer_zug = self.nachricht[3:]
                log.eintrag('Gegnerischer Zug: ' + gegnerischer_zug )
                
                if self.nachricht[2] == '1':
                        temp_liste = [int(x) for x in 
self.nachricht[4:].split()]
                        gegnerischer_stein = temp_liste.pop(0), 
temp_liste.pop(0)
                        x1, y1 = temp_liste.pop(0), temp_liste.pop(0)
                        x2, y2 = temp_liste.pop(0), temp_liste.pop(0)
                        global spielfeld
                        spielfeld[x1][y1] = gegnerischer_stein[0]
                        spielfeld[x2][y2] = gegnerischer_stein[1]
                        log.eintrag('Neues Feld: ' + str(spielfeld))
                        
        def erster_zug(self):
                """Erster Zug
                Der erste Zug unterscheidet sich von den
                nachfolgenden. Deswegen erhält er eine eigene
                Logik.
                """
                for x in spieler_steine:
                        if x[0] == x[1]:
                                stein = x
                        else:
                                stein = random.choice(spieler_steine)
                spieler_steine.remove(stein)
                
                if stein[0] == 0:
                        anzulegender_stein = 0, 5
                elif stein[0] == 1:
                        anzulegender_stein = 10, 10
                elif stein[0] == 2:
                        anzulegender_stein = 5, 0
                elif stein[0] == 3:
                        anzulegender_stein = 10, 5
                elif stein[0] == 4:
                        anzulegender_stein = 0, 0
                elif stein[0] == 5:
                        anzulegender_stein = 5, 10
                        
                umliegende_spielfelder = self.nachbarfelder(anzulegender_stein)
                
                x1, y1 = umliegende_spielfelder.pop(0)
                print x1, y1
                x2, y2 = umliegende_spielfelder.pop(0)
                print x2, y2
                
                zug = '3 ' + str(stein[0]) + ' ' + str(stein[1]) \
                           + ' ' + str(x1) + ' ' + str(y1) + ' ' \
                           + str(x2) + ' ' + str(y2) + '\n'
                           
                log.eintrag('Erster Zug: ' + zug )
                
                spielfeld[x1][y1] = stein[0]
                spielfeld[x2][y2] = stein[1]
                netzwerk.senden(zug)
                
        def ziehen(self):
                """Die zentrale Zuginstanz
                In dieser Funktion befindet sich die eigentlich
                Spiel-Logik.
                """
                stein = random.choice(spieler_steine)
                spieler_steine.remove(stein)
                zug = '3 ' + str(stein[0]) + ' ' + str(stein[1])
                
                global spielfeld

                while True:
                        print "Schleife 1"
                        x1, y1 = random.randrange(11), random.randrange(11)
                        richtung = random.randrange(6)
                        
                        while True:
                                print "Schleife 2"                              
        
                                x2, y2 = \
                                        self.nachbarfeld(x1, y1, richtung)
                                if x2 < 11 or y2 < 11 or \
                                   x2 >= 0 or y2 >= 0:
                                        break
                                         
                                                        
                        if spielfeld[x1][y1] == -1 and \
                           spielfeld[x2][y2] == -1:
                                break
                                                        
                zug = zug + ' ' + str(x1) + ' ' + str(y1) + ' ' \
                          + str(x2) + ' ' + str(y2) + "\n"
                        
                self.spielfeld_aktualisieren((x1, y1), (x2, y2), stein)
                
                log.eintrag(str(spielfeld))
                
                netzwerk.senden(zug)
                
        def nachbarfeld(self, x, y, richtung):
                """Nachbarfeld
                Gibt ein Nachbarfeld in Abhängigkeit von der Richtung zurück
                """
                if richtung == 0:
                        return x-1, y
                if richtung == 1:
                        return x, y+1
                if richtung == 2:
                        return x+1, y+1
                if richtung == 3:
                        return x+1, y
                if richtung == 4:
                        return x, y-1
                if richtung == 5:
                        return x-1, y-1
                        
        def nachbarfelder(self, (x, y)):
                """Liste mit Nachbarfeldern
                Gibt eine Liste mit Nachbarfeldern zurueck
                """
                liste = []
                for richtung in range(6):
                        xnachbar, ynachbar = self.nachbarfeld(x, y, richtung)
                        try:
                                xnachbar, ynachbar = 
self.feld_pruefen(xnachbar, ynachbar)
                                liste.append((xnachbar, ynachbar))
                        except ValueError:
                                pass
                        except TypeError, detail:
                                if detail == "unpack non-sequence":
                                        pass
                        
                print liste
                return liste                                    
                        
        def spielfeld_aktualisieren(self, koordinate1, koordinate2, stein):
                """Eigene Zuege nachtragen
                Mit dieser Funktion kann man die eigenen
                Züge in das Spielfeld einfügen lassen.
                """
                print koordinate1
                print koordinate2
                spielfeld[koordinate1[0]][koordinate1[1]] = stein[0]
                spielfeld[koordinate2[0]][koordinate2[1]] = stein[1]
                
        def feld_pruefen(self, x, y):
                if x and y < 11 and \
                   x and y >= 0:
                        print x, y
                        if spielfeld[x][y] == -1:
                                return (x, y)
                        else:
                                raise ValueError, 'Ungueltiges Feld'
                
                
# Die zentrale Endlosschleife
while True:
        
        log = Logger(log_datei)
        log.eintrag("*** Einfach Genial - Spiel ***\n")
        
        netzwerk = Netzwerk(port)
        netzwerk.verbinden()
        
        spiel_laufend = True
        
        runde = 0
        try:
                while spiel_laufend == True:
                
                        # jede der zurückgegebenen Instanzen
                        # hat eine Methode namens 'handle_message'
                        runde = runde + 1
                        log.eintrag('Durchlauf: ' + str(runde)+ '\n')
                        liste_instanzen = netzwerk.zug()
                        for instanz in liste_instanzen:
                                instanz.handle_message()
        except KeyboardInterrupt:
                s = "Vom Benutzer beendet."
                print s
                log.eintrag(s)
                netzwerk.beenden()
                break
        
        except:
                #print type(inst)
                #print inst.args 
                #print inst
                #x, y = inst
                #print 'x =', x
                #print 'y =', y
                #s = "Fehler aufgetreten: " + str(sys.exc_info()[0])
                #print s
                #log.eintrag(s)
                netzwerk.beenden()
                raise
                break

Other related posts:

  • » [software_challenge] v0002