Online Reversi


Auf einem 8×8-Brett legen zwei Spieler abwechslungsweise gelbe und rote Spielsteine. Zu Beginn des Spiels sind bereits je zwei gelbe und rote Steine in der Mitte des Spielbretts gelegt. Die weiteren Spielsteine können per Mausklick in leere Zellen gelegt werden, bei welchen mindestens eine der benachbarten Zellen oben, unten, links oder rechts belegt ist.

 
 
 
nicht erlaubt
 
erlaubt
 

Wird ein Stein gelegt, so werden alle gegnerischen Steine, die sich in Reihen oder Diagonalen zwischen dem neuen und bereits gelegten Steinen der eigenen Farbe befinden, durch Steine der eigenen Farbe ersetzt. Das Ziel des Spiels ist es, am Ende möglichst viele eigene Steine auf dem Brett zu haben. Das Spiel ist fertig, wenn alle Zellen belegt sind.

  Server
Client

Zuerst muss das Serverprogramm gestartet werden. Der Client beginnt das Spiel. Einige Funktionen im Server- und Clientprogramm sind identisch, insbesondere die Übeprüfung der Spielsituation nach jedem Zug. Es ist daher sinnvoll diese Funktionen in einer separaten Datei (reversilib.py) im gleichen Verzeichnis, wie das Server- und Client-Programm, zu speichern und diese zu importieren. Die importierten Funktionen müssen durch Voranstellen von "reversilib." aufgerufen werden.

So wie in den vorhergehenden Beispielen werden jeweils die x- und y-Koordinaten des Mausklicks übermittelt. Die Überprüfung des Spielsituation und das Kehren der Spielsteine erfolgt bei jedem Spieler autonom.

# ReversiServer.py

from gamegrid import *
from tcpcom import TCPServer
import reversilib
      
def onMousePressed(e):
    global isMyMove, location
    if not isMyMove or isOver:
          return
    location = toLocationInGrid(e.getX(), e.getY())
    if getOneActorAt(location) == None and reversilib.hasNeighbours(location):
        stone = Actor("sprites/token.png", 2)
        addActor(stone, location)
        stone.show(1)
        reversilib.checkStones(1, location)
        refresh()
        server.sendMessage(str(location.x) + str(location.y)) # send location
        isMyMove = False
        setStatusText("Wait!")
        if len(getOccupiedLocations()) == 64:    
           reversilib.endOfGame()
           server.sendMessage("end")

def onNotifyExit():
    server.terminate()
    dispose()
    
def onStateChanged(state, msg):
    global isMyMove,imegeID, location
    if state == TCPServer.PORT_IN_USE:
        setStatusText("TCP port occupied. Restart IDE.")
    if state == TCPServer.LISTENING:
        setStatusText("Waiting for a partner to play")        
    if state == TCPServer.CONNECTED:
        setStatusText("Client connected. Wait for partner's move!")
    elif state == TCPServer.MESSAGE: 
        if msg == "end":
            reversilib.endOfGame()
        else:
            x = int(msg[0])
            y = int(msg[1])
            location = Location(x, y)            
            stone = Actor("sprites/token.png", 2)
            addActor(stone, location)          
            stone.show(0)
            reversilib.checkStones(0, location)
            refresh()        
            isMyMove = True
            setStatusText("Make your move!")
 
isMyMove = False   
makeGameGrid(8, 8, 60, Color.gray, False, mousePressed = onMousePressed, notifyExit = onNotifyExit)
addStatusBar(30)
reversilib.initGame()
show()
port = 5000
server = TCPServer(port, stateChanged = onStateChanged)
isOver = False
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

----------------------------------------------------------------------------------------------------------------------------------
# ReversiClient.py

from gamegrid import *
from tcpcom import TCPClient
import reversilib                                                                            
      
def onMousePressed(e):
    global isMyMove, location
    if not isMyMove or isOver:
        return
    location = toLocationInGrid(e.getX(), e.getY())
    if getOneActorAt(location) == None and reversilib.hasNeighbours(location):
        stone = Actor("sprites/token.png", 2)
        addActor(stone, location)
        stone.show(0)
        reversilib.checkStones(0, location)
        refresh()
        client.sendMessage(str(location.x) + str(location.y)) # send location
        isMyMove = False
        setStatusText("Wait!")
        if len(getOccupiedLocations()) == 64:    
           reversilib.endOfGame()
           client.sendMessage("end")

def onNotifyExit():
    client.disconnect()
    dispose()
   
def onStateChanged(state, msg):
    global isMyMove, imegeID, location
    if state == TCPClient.CONNECTED:
        setStatusText("Connection established. You play!")
        isMyMove = True
    elif state == TCPClient.CONNECTION_FAILED:
        setStatusText("Connection failed")
    elif state == TCPClient.DISCONNECTED:
        setStatusText("Server died")
        isMyMove = False
    elif state == TCPClient.MESSAGE:                       
        if msg == "end":
           reversilib.endOfGame()
        else:
            x = int(msg[0])
            y = int(msg[1])
            location = Location(x, y)           
            stone = Actor("sprites/token.png", 2)
            addActor(stone, location)         
            stone.show(1)
            reversilib.checkStones(1, location)
            refresh()
            isMyMove = True
            setStatusText("Make your move!")
 
isMyMove = False  
makeGameGrid(8, 8, 60, Color.gray, False, mousePressed = onMousePressed, notifyExit = onNotifyExit)
addStatusBar(30)
reversilib.initGame()
show()
host = "localhost"
port = 5000
client = TCPClient(host, port, stateChanged = onStateChanged)
client.connect()
isOver = False
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

-----------------------------------------------------------------------------------------------------------------------------------

# reversilib.py

from gamegrid import *

def initGame():
    yellow = Actor("sprites/token.png", 2)
    yellow2 = Actor("sprites/token.png", 2)
    red = Actor("sprites/token.png", 2)
    red2 = Actor("sprites/token.png", 2)
    addActor(yellow, Location(3, 3))
    addActor(yellow2, Location(4, 4))
    addActor(red, Location(4, 3))
    addActor(red2, Location(3, 4))
    yellow.show(0)
    yellow2.show(0)
    red.show(1)
    red2.show(1)

#Checks if cell has a neighbour in the north, east, south or west
def hasNeighbours(loc):
    locs = toList(loc.getNeighbourLocations(0.5))
    for i in range(4):
        if getOneActorAt(locs[i]) != None:
            return True
    return False

# Check for stones in all 8 directions and if they can be turned add list
def checkStones(imageID, location):
    for c in range (0, 360, 45):
        actors = []
        loc = location.getNeighbourLocation(c)
        a = getOneActorAt(loc)
        hasSameImageID = False
        while a != None and not hasSameImageID:
            if a.getIdVisible() != imageID:
                actors.append(a)
                loc = loc.getNeighbourLocation(c)
                a = getOneActorAt(loc)          
            else:    
                if a.getIdVisible() == imageID:
                    hasSameImageID = True
        # Turn stones 
        if hasSameImageID:
            for actor in actors:
                actor.show(imageID)  
                
# endOfGame
def endOfGame():
    countYellow = 0
    countRed = 0
    all = getOccupiedLocations()
    for lc in all:
        if getOneActorAt(lc).getIdVisible() == 0:
           countYellow += 1
        else:
           countRed += 1
    if len(all) == 64:
        if countRed > countYellow:
            setStatusText("Game over. Red wins - " + str(countRed) + ":" + str(countYellow))
        elif countRed < countYellow:
            setStatusText("Game over. Yellow wins - " + str(countYellow) + ":" + str(countRed))
        else:
            setStatusText("The game ended in a tie")  
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

 

Erklärungen zum Programmcode:

reversilib.initGame(): Erzeugt das Spielfeld mit 2 roten und gelben Steinen. Diese Funktion ist in reversilib.py definiert
locs = toList(loc.getNeighbourLocations(0.5)): Liste der 4 direkt benachbarten Zellen
for c in range (0, 360, 45): 8 Richtungen 0, 45, 90, 135,...315
loc = location.getNeighbourLocation(c): Liefert benachbarte Zellen, die in der Richtung c liegen
all = getOccupiedLocations(): Liste aller besetzten Zellen