TigerJython xx
für Gymnasien

Online Four-in-a-Row (4 gewinnt ) mit MQTT


Four-in-a-Row ist ein Zweipersonen-Strategiespiel. Das Spielbrett besteht aus sieben Spalten (senkrecht) und sechs Reihen (waagrecht). Die Spieler positionieren abwechselnd ihre Spielsteine, indem sie den Spielstein mit Mausklick im oberen Kanal über die gewählte Spalte setzen. Der Spielstein bewegt nach unten und besetzt den untersten freien Platz der Spalte. Gewinner ist der Spieler, der es als Erster schafft, vier seiner Spielsteine waagerecht, senkrecht oder diagonal in eine Linie zu bringen. Das Spiel endet unentschieden, wenn das Spielbrett komplett gefüllt ist, ohne dass ein Spieler eine Viererlinie gebildet hat.

 

  Player 0
Player 1

Die beiden Spieler wählen das gleiche Topic /swissgame/four in a row und müssen vor dem Spielbeginn die Programmzeile player = 0 bzw. player = 1 ergänzen. Der Player 0 beginnt.

# FourInARow.py

from gamegrid import *
from mqttclient import GameClient
import fourlib                                                                    

player = x # set player = 0 or player = 1
myTopic = "/swissgame/four_in_a_row"

def onMousePressed(e):
    global isMyMove, location
    if not isMyMove or fourlib.isOver:
          return
    location = toLocationInGrid(e.getX(), e.getY())
    token = fourlib.Token(player)
    addActor(token, location, Location.SOUTH)   
    client.sendMessage(str(location.x)) # send location
    isMyMove = False
    setStatusText("Wait!")    

def onNotifyExit():
    client.disconnect()
    dispose()
    
def onStateChanged(state):
    global isMyMove
    if state == "CONNECTING":
        setStatusText("Connecting to broker...")    
    elif state == "CONNECTED":
        setStatusText("Connected. Waiting for partner...")    
    elif state == "READY":
        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, location
    x = int(msg[0])        
    location = Location(x, 0)            
    token = fourlib.Token((player + 1) % 2)
    addActor(token, location, Location.SOUTH)     
    isMyMove = True
    setStatusText("Make your move!")
    
makeGameGrid(7, 7, 70, None, "sprites/connectbg.png", False,
    mousePressed = onMousePressed, notifyExit = onNotifyExit)
setBgColor(makeColor("white"))
addStatusBar(30)
isMyMove = False 
show()
setSimulationPeriod(30)
doRun()
setTitle("Player #" + str(player))
host = "m2m.eclipse.org"
client = GameClient(onStateChanged, onMessageReceived, myTopic)
client.connect(host)
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

Die Klasse Token und die Funktionen zur Überprüfung der Spielsituation werden in der Datei fourlib.py gespeichert und im Hauptprogramm mit import fourlib importiert. 
# fourlib.py

from gamegrid import *

isOver = False

#----------class Token -------------------------------
class Token(Actor):
    def __init__(self, player):
        Actor.__init__(self, "sprites/token.png", 2)
        self.player = player
        self.show(player)
        self.nb = 0

    def act(self):
        global isOver
        nextLoc = Location(self.getX(), self.getY() + 1)
        if (getOneActorAt(nextLoc) == None and self.isMoveValid()):
            if self.nb == 6:
                self.nb = 0
                self.setLocationOffset(Point(0, 0))
                self.move()
            else:
                self.setLocationOffset(Point(0, 10 * self.nb))
            self.nb = self.nb + 1 
        else:  # arrived
            self.setActEnabled(False)  # old token will stay where it is
            if checkOver(self.getLocation()):
                if self.player == 0:
                    won = "Yellow"
                else:
                    won = "Red"    
                setStatusText("Game Over, player " + won + " won!")             
                isOver = True   

#----------check Game over-------------------------------------
def getId(x, y):
    loc = Location(x, y)
    if getOneActorAt(loc) == None:
        return -1
    else:
        return getOneActorAt(loc).getIdVisible()

#check for four
def checkDiagonal(col, row):
    for j in range(4):
        nb = 0
        for i in range(4):
            if (col + i - j) >= 0 and (col + i - j) < 7 and (row + i - j) >= 1 \
               and (row + i - j) < 7 \
               and getId(col + i - j, row + i - j) == getId(col, row):
                nb = nb + 1
        if nb >= 4:
            return True
    return False

def checkDiagonal2(col, row):
    for j in range(4):
        nb = 0
        for i in range(4):
            if (col - i + j) >= 0 and (col - i + j) < 7 \
               and (row + i - j) >= 1 and (row + i - j) < 7 \
               and getId(col - i + j, row + i - j) == getId(col, row):
                 nb = nb + 1
        if nb >= 4:
            return True
    return False

def checkHorizontal(col, row):
    nb = 1
    i = 1
    while col - i >= 0 and getId(col - i, row) == getId(col, row):
        nb = nb + 1
        i += 1
    i = 1
    while col + i < 7 and getId(col + i, row) == getId(col, row):
        nb = nb + 1
        i += 1
    return nb >= 4

def checkVertical(col, row):
    nb = 1
    i = 1
    while row + i < 7 and getId(col, row + i) == getId(col, row):
       nb = nb + 1
       i += 1
    return nb >= 4

#return true, if four in a row
def checkOver(loc):
    col = loc.x
    row = loc.y
    return (checkVertical(col, row) 
      or checkHorizontal(col, row)
      or checkDiagonal(col, row)
      or checkDiagonal2(col, row)) 
Programmcode markieren (Ctrl+C kopieren, Ctrl+V einfügen)

 

Erklärungen zum Programmcode:

class Token(): Die Spielsteine sind Objekte der Klasse Token(). Die Klasse verwendet zwei Spritebilder token_0.png für die gelben und token_1.png für die roten Steine. In der Methode act() wird die Bewegung der Spielsteine festgelegt
checkOver(loc) gibt True zurück, falls einer der Checks (horizontal, vertikal und beide Diagonalen) positiv ausfällt