lehrkraefte:blc:informatik:ffprg1-2024:raster-tictactoe

Tic Tac Toe

  • Legen Sie einen neuen Ordner 'tictactoe' and und speichern Sie darin die Dateien der Basis für ein Raster Spiel.
  • Speichern Sie im gleichen Ordner auch folgende beiden Bilder (gemacht mit dem sehr zu empfehlenden OpenSource-Programm Inkscape:
  • Fügen Sie in der Datei raster.css folgenden CSS-Code hinzu:
.wert1 {
    background-image: url("cross.svg");
    background-size: cover;
}
.wert2 {
    background-image: url("dot.svg");
    background-size: cover;
}
  • In der Datei mygame.js
    • entfernen Sie den Aufruf von Raster.addColorRules,
    • passen Sie die Grösse auf 3 mal 3 an,
    • fügen Sie eine Variable currentPlayer hinzu, die angibt, welcher Spieler (1 oder 2) gerade am Zug ist.
    • Beginnen Sie das Spiel im clickCallback zu programmieren (mit den Variablen meinRaster und currentPlayer). Dabei soll einfach abwechselnd auf leeren Feldern gezogen werden können.
    • Fügen Sie eine weitere Variable cellsPlayed hinzu, die zählt, wie viele Zellen schon belegt sind.
    • Programmieren Sie eine Unterfunktion reset, die das Spiel und alle nötigen Variablen zurücksetzt.
    • Wenn geklickt wird und alle Zellen schon voll sind, soll das Spiel neu starten.

Lösungsvorschlag

Lösungsvorschlag

window.addEventListener('load', function() {
 
    let meinRaster = new Raster(3,3);
    let currentPlayer = 1;
    let cellsPlayed = 0;
 
    function reset() {
        currentPlayer = 1;
        cellsPlayed = 0;
        for (let x=0; x<3; x++) {
            for (let y=0; y<3; y++) {
                meinRaster.setValue(x,y,0);
            }
        }
    }
 
    // Callback für einen Klick definieren
    meinRaster.clickCallback = function(x, y) {
        if (cellsPlayed==9) {
            reset();
            return;
        }
        let v = meinRaster.getValue(x,y);
        if (v!=0) {
            return;
        }
        meinRaster.setValue(x,y,currentPlayer);
        currentPlayer = 3-currentPlayer;
        cellsPlayed++;
    }
});

In der Datei mygame.js, fügen Sie eine weitere Unterfunktion winner hinzu, die folgende Werte zurückgibt:

  • 0, wenn niemand 3 in einer Reihe hat
  • 1 oder 2, wenn Spieler 1 oder Spieler 2 gewonnen hat.

Hinweise:

  • Schreiben Sie zusätzlich eine Funktion sindsDrei(x,y,vx,vy), die true ergibt, wenn drei gleiche Werte >=1 vom Startpunkt x,y, in Richtung des Vektors (vx,vy) anzutreffen sind. Sonst false.
  • Rufen Sie die Funktion sindsDrei in der Funktion winner unter anderem in einer for-schlaufe auf.

Teillösungsvorschlag

Teillösungsvorschlag

    function sindsDrei(x,y,vx,vy) {
        let w = meinRaster.getValue(x,y);
        if (w==0) return false;
        for (let i=0; i<3; i++) {
            if (meinRaster.getValue(x,y)!=w) return false;
            x+=vx;
            y+=vy;
        }
        return true;
    }
 
    function winner() {
        for (let i=0; i<3; i++) {
            if (sindsDrei(i,0,0,1)) return meinRaster.getValue(i,0);  // Vertikal
            if (sindsDrei(0,i,1,0)) return meinRaster.getValue(0,i);  // Horizontal
        }
        if (sindsDrei(0,0,1,1)) return meinRaster.getValue(0,0);  // Diagonale in Richtung (1,1)
        if (sindsDrei(2,0,-1,1)) return meinRaster.getValue(2,0);  // Diagonale in Richtung (-1,1)
        return 0;
    }

Lösungsvorschlag aus der Stunde

Lösungsvorschlag aus der Stunde

// Erst mal alles Laden, erst dann an der Webseite
// Dinge ändern (die sonst noch gar nicht existieren würden)
window.addEventListener('load', function() {
 
 
    // Raster anlegen
    // Diese Variable ist ab hier auch in Unterfunktionen
    // definiert und verwendbar
    let meinRaster = new Raster(13,13);
    let currentPlayer = 1;
 
    function reset() {
        meinRaster.fill(0);
        currentPlayer = 1;
    }
    function zaehlen(x,y,vx,vy, markieren=false) {
        let count = function(x,y,vx,vy) {
            let anzahl = 1;
            let wert = meinRaster.getValue(x,y);
            let [a,b] = [x+vx,y+vy];
            while (meinRaster.isOn(a,b) && meinRaster.getValue(a,b)==wert) {
                if (markieren) {
                    meinRaster.setValue(a,b,wert+2);
                }
                anzahl++;
                [a,b] = [a+vx, b+vy];
            }
            return anzahl;
        }
        let anzahl = count(x,y,vx,vy, markieren)+count(x,y,-vx,-vy, markieren)-1;
        if (markieren) {
            meinRaster.setValue(x,y,meinRaster.getValue(x,y)+2);
        }
 
        return anzahl;
    }
 
    function hasWon(x,y) {
        for (let v of [[1,0],[1,1],[0,1],[-1,1]]) {
            if (zaehlen(x,y,v[0],v[1])>=5) {
                zaehlen(x,y,v[0],v[1],true);
                return true;
            }
        }
    }
    // Callback für einen Klick definieren
    meinRaster.clickCallback = function(x, y) {
        let v = meinRaster.getValue(x,y);
        if (v==0) {
            meinRaster.setValue(x,y,currentPlayer);
            if (hasWon(x,y)) {
                console.log(`Player ${currentPlayer} hat gewonnen!`);
            }
            currentPlayer = 3-currentPlayer;
        }
    };
 
    this.document.getElementById('resetknopf').addEventListener('click', reset);
 
});

Ziel ist es, die gewinnende Dreierreihe zu markieren.

  • Fügen Sie dazu in der Datei raster.css zwei weitere Klassen wert3 und wert4 hinzu, um das Aussehen der gewinnenden Zellen für Spieler 1 und 2 festzulegen.
  • In der Funktion sindsDrei, fügen Sie unmittelbar vor dem return true noch eine Schlaufe hinzu, die den Wert der gewinndenden Zellen um 2 erhöht.

Lösungsvorschlag

Lösungsvorschlag

.wert3 {
    background-image: url("cross.svg");
    background-color: lightcoral;
    background-size: cover;
}
.wert4 {
    background-image: url("dot.svg");
    background-color: skyblue;
    background-size: cover;
}
        for (let i=0; i<3; i++) {
            x-=vx;
            y-=vy;
            meinRaster.setValue(x,y,w+2);
        }
  • lehrkraefte/blc/informatik/ffprg1-2024/raster-tictactoe.txt
  • Last modified: 2024/05/17 13:10
  • by Ivo Blöchliger