Tic-Tac-Toe ist ein altes Strategiespiel, dessen Geschichte sich bis ins 12. Jahrhundert v. Chr. zurückverfolgen lässt. Auf einem 3×3 Felder grossen Spielfeld setzen die beiden Spieler abwechselnd ihre Zeichen. Der Spieler, der als erstes drei seiner Zeichen in eine Reihe, Spalte oder eine der beiden Diagonalen setzen kann, gewinnt. Wenn beide Spieler optimal spielen, kann keiner gewinnen, und es kommt zu einem Unentschieden. |
Player 0 |
Player 1 |
Die beiden Spieler verwenden das gleiche Topic /swissgame/tic-tac-toe. Im Programm legen Sie mit player = 0 bzw. player = 1 fest, wer als erster zum Zug kommt und starten das Spiel. Der Status der Verbindung wird mit der Callbackfunktion onStateChanged() überwacht und in der Statuszeile angezeigt. Sobald die beiden Spielpartner verbunden sind (Status READY) kommt der Player 0 zuerst zum Zug und in seiner Statuszeile erscheint "Make a move!".
Die Zeichen "x" und "o" werden per Mausklick gesetzt. Dabei wird jeweils die x- und y-Koordinate des Mausklicks zum Spielpartner gesendet und das gesetzte Zeichen mit der Funktion setPattern() in der Belegung des Spielbretts eingetragen. Die Überprüfung des Spielsituation erfolgt nach jedem Zug mit der Funktion checkGameState() mit folgendem Trick: Die horizontale, vertikale und diagonale Belegung des Spielbretts wird in einem kommagetrennten Stringmuster der Form XOX,XX- ,O-O, ... dargestellt (leere Zellen erhalten das Zeichen '-'). Wenn XXX bzw. OOO in diesem String vorkommen, hat ein Spieler gewonnen.
# TicTacToe.py from gamegrid import * from mqttclient import GameClient player = x # set player = 0 or player = 1 myName = "Player " myTopic = "/swissgame/tic-toc-toe" def onMousePressed(e): global isMyMove if not isMyMove or isOver: return loc = toLocationInGrid(e.getX(), e.getY()) if getOneActorAt(loc) != None: return mark = Actor("sprites/mark.gif", 2) addActor(mark, loc) client.sendMessage(str(loc.x) + str(loc.y)) # send location setStatusText("Wait for partner's move!") mark.show(player) refresh() checkGameState() isMyMove = False def setPattern(x, y): global pattern loc = Location(x, y) a = getOneActorAt(loc) if a == None: pattern += '-' elif a.getIdVisible() == 0: pattern += 'O' elif a.getIdVisible() == 1: pattern += 'X' def checkGameState(): # Convert board state into string pattern global pattern, isOver pattern = "" # Horizontal for y in range(3): for x in range(3): setPattern(x, y) pattern += ',' # Separator # Vertical for x in range(3): for y in range(3): setPattern(x, y) pattern += ',' # Diagonal for x in range(3): setPattern(x, x) pattern += ',' for x in range(3): setPattern(x, 2 - x) if "XXX" in pattern: setStatusText("X won") isOver = True elif "OOO" in pattern: setStatusText("O won") isOver = True elif not "-" in pattern: setStatusText("Board full") isOver = True def onStateChanged(state): global isMyMove if state == "CONNECTING": setStatusText("Connecting to broker...") elif state == "CONNECTED": setStatusText("Connected. Waiting for partner...") elif state == "READY": setTitle("From:" + client.getPartnerName() + "@" + client.getPartnerAddress()) if player == 0: setStatusText("Make a move!") isMyMove = True else: setStatusText("Wait for partner's move!") elif state == "DISCONNECTED": setStatusText("Partner disconnected!") isMyMove = False def onMessageReceived(msg): global isMyMove if msg == "DISCONNECT": setStatusText("Partner disconnected") isMyMove = False return x = int(msg[0]) y = int(msg[1]) loc = Location(x, y) mark = Actor("sprites/mark.gif", 2) addActor(mark, loc) mark.show((player + 1) % 2) refresh() setStatusText("Make a move!") checkGameState() isMyMove = True def onNotifyExit(): client.disconnect() dispose() makeGameGrid(3, 3, 100, Color.black, False, mousePressed = onMousePressed, notifyExit = onNotifyExit) setBgColor(makeColor("greenyellow")) addStatusBar(30) show() setTitle("TicTacToe") isOver = False isMyMove = False setTitle("Player #" + str(player)) host = "m2m.eclipse.org" client = GameClient(onStateChanged, onMessageReceived, myTopic) client.setName(myName + str(player)) client.connect(host) |
Erklärungen zum Programmcode:
if getOneActorAt(loc) != None: Belegte Felder dürfen nicht gewählt werden | |
client.sendMessage(str(loc.x) + str(loc.y)): Die Koordinaten des Mausklicks werden als String gesendet (zwei Ziffern zwischen 0 und 2) | |
def setPattern(x, y): Schreibt eines der Zeichen 'X', 'O', bzw.' -' in das Stringmuster | |
def checkGameState(): Durchläuft alle Zeilen, Spalten und Diagonalen und stellt die Zellenbelegung durch ein Stringmuster dar. Danach wird überprüft, ob einer Zeile, Spalte oder Diagonale drei gleiche Zeichen vorkommen. Falls das Stringmuster kein Zeichen '-' enthält, ist das Brett voll |