Tjoar, um mich ein bisschen mit Klassen und Objekten zu beschäftigen (wenn auch nur grob^^), wollte ich einfach mal ein konsolenbasiertes TicTacToe-Spiel entwerfen. Die Nummernblöcke auf der Tastatur dienen dabei quasi als Eingabefeld.
Der Code ist in Python2 geschrieben, wg. dem print-Statement nicht in Python3 aufrufbar. Ich habe mich dabei bemüht, Spiellogik und Ausgabe so gut es geht zu trennen und hoffe, dass ich einigermaßen nachvollziehbar programmiert habe. Vorallem, da ich mit OOP eher theoretische Erfahrung habe, weiß ich nicht, inwieweit mein Code "brauchbar" ist (im Sinne von: "Diesen Programmierstil kann ich beibehalten" oder auch "wirf den Programmierstil so weit es geht über den Haufen"; sinnvolle Verwendung von Klassen/Objekten?). Ich würde mich dementsprechend über Feedback und Verbesserungsvorschläge freuen
Der Quellcode:
http://pastebin.com/NgeK05zS#
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from sys import exit
class Game():
''' Verwaltet das Spielfeld und die Spieler '''
constants = {
"EMPTY" : " ",
"SYMBOL_PLAYER_1" : "X",
"SYMBOL_PLAYER_2" : "O",
}
def __init__(self):
# Das Spielfeld generieren
self.gamefield = [
[
Game.constants["EMPTY"]for i in range(3)
]
for j in range(3)
]
# Die Spieler generieren
self.players = (Player(Game.constants["SYMBOL_PLAYER_1"], True),
Player(Game.constants["SYMBOL_PLAYER_2"])
)
def switchPlayersTurn(self):
''' wechselt, welcher Spieler gerade dran ist '''
for player in self.players:
player.turn = not player.turn
def place(self, (ypos, xpos)):
''' Platziert das Spielerobjekt im angegebenen Feld '''
for player in self.players:
if player.turn is True:
self.gamefield[ypos][xpos] = player.char
break
def isPlacePossible(self, (ypos, xpos)):
''' Gibt zurück, ob eine Platzierung möglich ist '''
if self.gamefield[ypos][xpos] == Game.constants["EMPTY"]:
return True
else:
return False
def isSomeoneWinner(self):
''' Prüft, ob ein Spieler gewonnen hat '''
# Waagrechte Prüfung
for x in self.gamefield:
for player in self.players:
if x.count(player.char) == 3:
return True
# Senkrechte Prüfung
for x in range(3):
for player in self.players:
if self.gamefield[0][x] == player.char and \
self.gamefield[1][x] == player.char and \
self.gamefield[2][x] == player.char:
return True
# Diagonale Prüfung
for player in self.players:
if self.gamefield[0][0] == player.char and \
self.gamefield[1][1] == player.char and \
self.gamefield[2][2] == player.char:
return True
elif self.gamefield[0][2] == player.char and \
self.gamefield[1][1] == player.char and \
self.gamefield[2][0] == player.char:
return True
return False
def isGamefieldFull(self):
''' Prüft, ob das Spielfeld voll und keine Züge mehr möglich sind '''
for x in self.gamefield:
for y in x:
if y == Game.constants["EMPTY"]:
return False
return True
class GUI():
''' Stellt Funktionalität für eine grafische Ausgabe bereit '''
def __init__(self, game):
self.game = game
def showPlayersTurn(self):
''' Zeigt, welcher Spieler an der Reihe ist '''
if self.game.players[0].turn is True:
print "Spieler 1 ist an der Reihe!"
elif self.game.players[1].turn is True:
print "Spieler 2 ist an der Reihe!"
def showGamefield(self):
''' Stellt das Spielfeld in ASCII-Zeichen dar '''
# TODO: Komplizierter gings nicht, oder?
j = 0
for x in reversed(self.game.gamefield):
i = 0
for y in x:
print y,
if i != 2:
print "|",
i += 1
if j < 2:
print "\n--+---+--"
j += 1
print
def showPlaceNotPossible(self):
print "An der Position kannst du nicht setzen!"
def showOptions(self):
print "Tasten auf dem Nummernblock druecken, um die Position",
print "zu bestimmen:"
def showGamefieldIsFull(self):
print "Das Spielfeld ist voll, und niemand hat gewonnen!"
def showWinner(self):
print "Herzlichen Glueckwunsch, Spieler",
if self.game.players[0].turn is True:
print "1",
else:
print "2",
print "hat das Spiel gewonnen!"
def waitForInput(self):
# TODO: Fehlerprüfung
return int(raw_input())
class Player():
''' Stellt Spieler bereit '''
def __init__(self, char=" ", turn=False):
self.char = char # "Symbol" des Spielers, entweder O oder X
self.turn = turn # ob der Spieler gerade dran ist
class Program():
''' Das Programm vermengt alles zu einem schönen Brei^^ '''
def convertInput(self, input):
'''
Diese Methode wandelt die Eingabe des Nummernblocks um.
Da die Klasse Game() nur mit Y- und X-Koordinaten etwas an-
fangen kann, der Benutzer aber nur ein Zeichen beim
Nummernblock eintragen muss, muss eine Methode her, die dieses
Zeichen in Y- und X-Koordinaten umwandelt. Die Game()-Klasse
kann (soll?) ja nicht wissen, WIE der Input vonstatten kommt,
es soll nur mit den richtigen Daten gefüttert werden.
'''
input -= 1
xpos = input % 3
ypos = input // 3
return ypos, xpos
def run(self):
game = Game()
gui = GUI(game)
gui.showGamefield()
running = True
while running:
gui.showPlayersTurn()
gui.showOptions()
key = gui.waitForInput()
y, x = self.convertInput(key)
if game.isPlacePossible((y, x)) is False:
gui.showPlaceNotPossible()
else:
game.place((y, x))
if game.isSomeoneWinner():
gui.showWinner()
running = False
elif game.isGamefieldFull():
gui.showGamefieldIsFull()
running = False
else:
game.switchPlayersTurn()
gui.showGamefield()
if __name__ == "__main__":
Program().run()