Created
March 19, 2014 20:38
-
-
Save anonymous/9650662 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from sys import exit | |
import controls | |
import events | |
import models | |
import views | |
def main(): | |
# Die Ganzen Module miteinander bekanntmachen | |
# und den EventManager durchreichen | |
evManager = events.EventManager() | |
viewer = views.CmdViewer(evManager) | |
controller = controls.CmdController(evManager) | |
game = models.Game(evManager) | |
four_in_a_row = controls.CPUSpinner(evManager) | |
# Als Beobachter brauchen beide Zugriff aufs Spiel | |
viewer.game = game | |
controller.game = game | |
# Im Hauptmenue anfangen und losstarten | |
evManager.send(events.SetEventState("main menu")) | |
four_in_a_row.run() | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import events | |
# Fix fuer Python2-/3-Kompatibilitaet | |
try: | |
input = raw_input | |
except NameError: | |
pass | |
# Die Funktion ist ein uebler Hack wegen dem evManager | |
def check_input(min, max, evManager): | |
"""Funktion, die den Benutzer nach einer Eingabe fragt. | |
Es werden min- und max-Werte mitgegeben. Die Funktion verlangt | |
solange eine Eingabe, bis eine korrekte geliefert wurde. | |
""" | |
while True: | |
keyb_key = None | |
try: | |
keyb_key = int(input()) | |
if keyb_key < min or keyb_key > max: | |
raise ValueError | |
except (SyntaxError, NameError, EOFError, ValueError): | |
evManager.send(events.WrongInput()) | |
else: | |
break | |
return keyb_key | |
class CmdController(object): | |
def __init__(self, evManager): | |
self.evManager = evManager | |
self.evManager.register(self) | |
self.keyb_key = None | |
def notify(self, event): | |
if self.evManager.state == "game running": | |
self.control_game(event) | |
elif self.evManager.state == "main menu": | |
self.control_mainmenu(event) | |
def control_game(self, event): | |
if isinstance(event, events.Tick): | |
self.keyb_key = check_input(0, 7, self.evManager) | |
if self.keyb_key == 0: | |
self.evManager.send(events.QuitGame()) | |
else: | |
# -1, um Die Zaehlung Mensch vs. Programmierer | |
# auszugleichen. Ein Programmierer faengt immer bei 0 | |
# das Zaehlen an ;) | |
self.evManager.send( | |
events.RequestDrop(self.game.player, self.keyb_key - 1)) | |
def control_mainmenu(self, event): | |
#print event | |
#exit() | |
if isinstance(event, events.Tick): | |
self.keyb_key = check_input(1, 2, self.evManager) | |
if self.keyb_key == 1: | |
self.evManager.send(events.SetEventState("game running")) | |
else: | |
self.evManager.send(events.QuitProgram()) | |
class CPUSpinner(object): | |
def __init__(self, evManager): | |
self.evManager = evManager | |
self.evManager.register(self) | |
self.running = True | |
def run(self): | |
while self.running: | |
self.evManager.send(events.Tick()) | |
def notify(self, event): | |
if isinstance(event, events.QuitProgram): | |
self.running = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
class EventManager(object): | |
"""EventManager zum Sammeln von Events. | |
Mit dem EventManager ist es moeglich, mehrere sog. Listener zu | |
registrieren (Methode "register"), und ihnen Events zu senden | |
(Methode "send"). Wenn ein Event gesendet wird, wird an allen | |
registrierten Listeners die Methode "notify" aufgerufen. | |
""" | |
def __init__(self): | |
self.listener = list() | |
self.register(self) | |
self.state = None | |
def register(self, listener): | |
"""Registriert einen Listener.""" | |
self.listener.append(listener) | |
def unregister(self, listener): | |
"""Deregistriert einen Listener.""" | |
if listener in self.listener: | |
del self.listener[listener] | |
def send(self, event): | |
"""Ruft bei allen Listeners die notify-Methode auf. | |
Das entsprechende Event wird als Parameter mitgesendet. | |
""" | |
for listener in self.listener: | |
listener.notify(event) | |
def notify(self, event): | |
"""Implementierung der notify-Methode. | |
Jeder Listener, der sich registriert, muss die notify-Methode | |
implementiert haben. | |
""" | |
if isinstance(event, SetEventState): | |
self.state = event.state | |
class Event(object): # Superklasse | |
pass | |
class SetEventState(Event): | |
def __init__(self, state): | |
self.state = state | |
class Tick(Event): | |
pass | |
class RequestDrop(Event): | |
def __init__(self, player, colnum): | |
self.player = player # Spielerobjekt | |
self.colnum = colnum # Spalte als Integer | |
class DropStone(Event): | |
def __init__(self, stone, colnum): | |
self.stone = stone | |
self.colnum = colnum | |
class DropNotPossible(Event): | |
def __init__(self, colnum): | |
self.colnum = colnum | |
class SwitchPlayers(Event): | |
pass | |
class WrongInput(Event): | |
pass | |
class QuitGame(Event): | |
pass | |
class QuitProgram(Event): | |
pass | |
class GameWon(Event): | |
def __init__(self, player): | |
self.player = player | |
class ReInitialize(Event): | |
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from sys import exit | |
import events | |
class Player(object): | |
"""Objekt Spieler.""" | |
def __init__(self, name, stone): | |
self.name = name | |
self.stone = stone | |
class Col(object): | |
"""Repraesentiert eine Spalte eines 4Gewinnt-Spiels.""" | |
def __init__(self, height=6, emptyvalue="."): | |
"""Erstellt eine Spalte.""" | |
self.reinitialize(height, emptyvalue) | |
def reinitialize(self, height=None, emptyvalue=None): | |
if height is not None: | |
self.height = height | |
if emptyvalue is not None: | |
self.emptyvalue = emptyvalue | |
self.col = [self.emptyvalue for _ in range(self.height)] | |
def __getitem__(self, key): | |
return self.col[key] | |
def __len__(self): | |
return len(self.col) | |
def is_drop_possible(self): | |
"""Prueft, ob ganz oben in der Spalte noch Platz frei ist. | |
Boolean als Rueckgabewert. | |
""" | |
return self.col[-1] == self.emptyvalue | |
def drop_stone(self, stone): | |
"""Wirft einen Stein in die Spalte rein. | |
Kein Rueckgabewert! "stone" sollte ein String mit | |
maximal einem Buchstaben sein. | |
Achtung: Keine Pruefung, ob ueberhaupt noch Platz fuer einen | |
Stein ist! Sonst wird der Stein an hoechster Stelle | |
ueberschrieben! | |
""" | |
# von Aussen nicht sichtbare Methode aufrufen, da niemand | |
# auf "row" zugreifen darf. | |
self.__drop_stone(stone, self.height - 1) | |
def __drop_stone(self, stone, row): | |
# Wenn der Stein noch nicht ganz unten angekommen ist UND sich | |
# unterhalb von der aktuellen Position noch Platz befindet, | |
# koennen wir noch eins nach unten wandern... | |
if row != 0 and self.col[row-1] == self.emptyvalue: | |
self.__drop_stone(stone, row-1) | |
else: | |
self.col[row] = stone | |
class Gamefield(object): | |
"""Repraesentiert das 4Gewinnt-Spielfeld mit seinen Spalten.""" | |
def __init__(self, width=7): | |
"""Erstellt das Spielfeld""" | |
self.width = width | |
self.rows = [Col() for _ in range(self.width)] | |
def __getitem__(self, key): | |
return self.rows[key] | |
def is_drop_possible(self, col): | |
"""Prueft, ob die Reihe voll ist. | |
col ist die angesprochene Spalte als Integer. | |
Boolean als Rueckgabewert.""" | |
return self.rows[col].is_drop_possible() | |
def drop_stone(self, stone, col): | |
"""Wirft einen Stein in die Reihe.""" | |
return self.rows[col].drop_stone(stone) | |
def get_row(self, row): | |
"""Gibt eine Reihe des Spielfelds zurueck.""" | |
return [col[row] for col in self.rows] | |
def is_full(self): | |
"""Prueft, ob das Spielfeld voll ist.""" | |
for col in self.rows: | |
if col.is_drop_possible(): | |
return True | |
return False | |
def reinitialize(self): | |
"""Setzt das Spielfeld wieder auf Anfang zurueck.""" | |
for col in self.rows: | |
col.reinitialize() | |
def is_someone_winner(self): | |
"""Prueft, ob jemand gewonnen hat.""" | |
# TODO: Alles katastrophal hier. Ich habe keine Ahnung, wie | |
# ich das alles besser hinbekomme :\ | |
# Senkrechte Pruefung | |
for col in self.rows: | |
for i in range(len(col)-3): | |
if col[i] == col.emptyvalue: | |
continue | |
elif col[i] == col[i+1] == col[i+2] == col[i+3]: | |
return True | |
# Waagrechte Pruefung... | |
for i in range(len(self.rows[0])): | |
row = self.get_row(i) | |
for j in range(len(row)-3): | |
if row[j] == self.rows[i].emptyvalue: | |
continue | |
elif row[j] == row[j+1] == row[j+2] == row[j+3]: | |
return True | |
# Diagonale Pruefung - Das Schlimmste zum Schluss :( ... | |
if self.__is_diagonal_winner(0, 3, 1): | |
return True | |
if self.__is_diagonal_winner(3, 6, -1): | |
return True | |
def __is_diagonal_winner(self, start, end, direction): | |
for i in range(start, end): | |
row1 = self.get_row(i) | |
row2 = self.get_row(i+direction) | |
row3 = self.get_row(i+(direction*2)) | |
row4 = self.get_row(i+(direction*3)) | |
for j in range(len(row1)-3): | |
if row1[j] == self.rows[0].emptyvalue: | |
continue | |
if row1[j] == row2[j+1] == row3[j+2] == row4[j+3]: | |
return True | |
return False | |
class Game(object): | |
"""Repraesentiert das Spiel.""" | |
def __init__(self, evManager): | |
self.evManager = evManager | |
self.evManager.register(self) | |
self.gamefield = Gamefield() | |
self.gamefield.game = self | |
self.player = Player("Programmierer", "X") | |
self.waiting_player = Player("Dummy-Spieler", "O") | |
def notify(self, event): | |
# Spieler fragt, ob er einen Stein werfen darf. | |
if isinstance(event, events.RequestDrop): | |
if self.gamefield.is_drop_possible(event.colnum): | |
self.evManager.send( | |
events.DropStone(event.player.stone, event.colnum)) | |
if self.gamefield.is_someone_winner(): | |
self.evManager.send(events.GameWon(self.player)) | |
self.evManager.send(events.QuitGame()) | |
self.evManager.send(events.SwitchPlayers()) | |
else: | |
self.evManager.send(events.DropNotPossible(event.colnum)) | |
elif isinstance(event, events.SwitchPlayers): | |
self.player, self.waiting_player = self.waiting_player, self.player | |
elif isinstance(event, events.DropStone): | |
self.gamefield.drop_stone(event.stone, event.colnum) | |
elif isinstance(event, events.QuitGame): | |
self.evManager.send(events.ReInitialize()) | |
self.evManager.send(events.SetEventState("main menu")) | |
elif isinstance(event, events.ReInitialize): | |
self.gamefield.reinitialize() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from sys import stdout | |
import events | |
class CmdViewer(object): | |
def __init__(self, evManager): | |
self.evManager = evManager | |
self.evManager.register(self) | |
def notify(self, event): | |
if self.evManager.state == "game running": | |
self.listen_game(event) | |
elif self.evManager.state == "main menu": | |
self.listen_mainmenu(event) | |
def listen_game(self, event): | |
if isinstance(event, events.Tick): | |
self.show_gamefield() | |
print("{} ist an der Reihe!".format(self.game.player.name)) | |
print("1-7 fuer Spalte, 0 fuer Beenden druecken!") | |
elif isinstance(event, events.DropNotPossible): | |
print("Sorry {},".format(self.game.player.name)) | |
print("hier kannst du nicht werfen!") | |
elif isinstance(event, events.WrongInput): | |
print("Fehlerhafte Eingabe!") | |
print("versucht es nochmal!") | |
elif isinstance(event, events.GameWon): | |
self.show_gamefield() | |
print("HERZLICHEN GLUECKWUNSCH!") | |
print("{} hat das Spiel gewonnen!".format(event.player.name)) | |
def show_gamefield(self): | |
"""Zeigt das Spielfeld an.""" | |
# TODO: Nicht gerade huebsch, die Methode :\ | |
print("") | |
# Erst die Zeilennummern ausgeben... | |
for i in range(1, len(self.game.gamefield.rows)+1): | |
stdout.write(str(i) + " ") | |
print("") | |
# ... dann den Rest vom Spielplan | |
height = self.game.gamefield.rows[0].height | |
for i in range(height -1, -1, -1): | |
for j, char in enumerate(self.game.gamefield.get_row(i)): | |
stdout.write(char) | |
if j != height: | |
stdout.write("|") | |
print("") | |
def listen_mainmenu(self, event): | |
if isinstance(event, events.Tick): | |
print("") | |
print("Hauptmenue 4gewinnt.py - MVC-Test") | |
print("---------------------------------") | |
print("1. Spiel starten") | |
print("2. Programm beenden") | |
elif isinstance(event, events.QuitProgram): | |
print("Vielen Dank fuer die Benutzung des Programms!") | |
print("Have a nice day! ;o)") | |
elif isinstance(event, events.WrongInput): | |
print("Fehlerhafte Eingabe, bitte wiederholen!") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment