Ankündigung

Einklappen
Keine Ankündigung bisher.

JavaScript Minesweeper

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • ByStones
    hat ein Thema erstellt JavaScript Minesweeper.

    JavaScript Minesweeper

    Hallo,
    ich habe heute ein kleines Minesweeper-Skript geschrieben, und wollte mal 2 Sachen fragen:
    1. Was haltet Ihr von der Umsetzung, wie kann man es gegebenenfalls besser machen ?
    2. Wie baue ich das Ganze in ein Objekt um, sodass man es wie jQuery benutzen kann ?

    Hier der Code:
    PHP-Code:
    var spielfeld = new Array();

    //Abmessung X
    var spielfeld_x 9;
    //Abmessung Y
    var spielfeld_y 9;
    //Anzahl der Minen
    var minen 10;

    //Spielfeld erzeugen
    for(var 0spielfeld_y+= 1) {
        
    spielfeld[y] = new Array();
        for(var 
    0spielfeld_x+= 1) {
            
    spielfeld[y][x] = null;
        }
    }

    //Aktuelle Anzahl der Minen
    var counter 1;
    do {
        
    //Zufällige X- und Y-Kooredinate für die Mine suchen
        
    Math.round(Math.random() * (spielfeld_x 1));
        
    Math.round(Math.random() * (spielfeld_y 1));

        
    //Wenn sich dort noch keine Mine befindet
        
    if (spielfeld[y][x] !== -1) {
            
    //Mine setzten
            
    spielfeld[y][x] = -1;

            
    //Minenzähler erhöhen
            
    counter += 1;
        }
    //Solange bis alle Minen verteilt sind
    } while (counter <= minen);

    //Hilfsarray um von einer Position alle umleigenden
    //anzusprechen
    var around = [
    {
        
    y: -1,
        
    x1
    }, {
        
    y: -1,
        
    x0
    }, {
        
    y: -1,
        
    x: -1
    }, {
        
    y0,
        
    x: -1
    },
    {
        
    y0,
        
    x1
    }, {
        
    y1,
        
    x1
    }, {
        
    y1,
        
    x0
    }, {
        
    y1,
        
    x: -1
    }
    ];

    //Anzahl der umliegenden Minen der aktuellen Position
    var minenAround 0;

    //Jedes Feld in einer Schleife durchlaufen
    $(spielfeld).each(function (i1y){
        $(
    y).each(function (i2x) {

            
    //Wenn an dieser Position eine Mine ist, dieses Feld überspringen
            //und mein nächsten Weitermachen
            
    if (spielfeld[i1][i2] == -1) {
                return;
            }

            
    //Die umliegenden Minen auf 0 setzten
            
    minenAround 0;

            
    //Das Hilfsarray durchlaufen
            
    $(around).each(function (kval){
                
    //Wenn die Position existiert...
                
    if (array_key_exists(i1 val.yspielfeld)
                    && 
    array_key_exists(i2 val.xspielfeld[i1 val.y])
                    
    //... und auf dieser Postion eine Mine liegt...
                    
    && spielfeld[i1 val.y][i2 val.x] == -1) {
                    
    //...den Minenzähler erhöhen
                    
    minenAround += 1;
                }
                
            });            

            
    //Die umliegenden Minen ins Array Schreiben
            
    spielfeld[i1][i2] = minenAround;
            
        });
    });

    function 
    getTdObject(i1i2) {
        
    //Das td-Objekt der Tabelle auf Basis der Koordinaten zurückgeben
        //Die + 1 deshalb bei :nth-child nicht mit 0 anfängt, sondern mit 1
        
    return $('.spielfeld tr:nth-child(' + (i1 1) + ') td:nth-child(' + (i2 1) + ')');
    }

    function 
    checkClicked(i1i2) {
        
    //Wurde auf das Spielfeld schoneinmal geklickt
        
    return getTdObject(i1i2).data('clicked') === true;
    }

    function 
    popupBlank(i1i2) {
        
    //Das Hilfsarray durchlaufen
        
    $(around).each(function (keyval){
            
    //Wenn die entsprechende Position existiert ...
            
    if (array_key_exists(i1 val.yspielfeld)
                && 
    array_key_exists(i2 val.xspielfeld[i1 val.y])
                
    //... und noch nicht darauf geklickt wurde
                //(Klick abfrage ist wichtig, sonst gibt es eine Endlosschleife) ...
                
    && !checkClicked(i1 val.yi2 val.x)) {
                
    //... einen Klick darauf ausführen
                
    getTdObject(i1 val.yi2 val.x).click();
            }

        });    
    }

    function 
    renderSpielfeld() {
        
    //Spielfeld erstellen
        
    var playground '<table class="spielfeld">';
        for(
    0spielfeld_y+= 1) {
            
    playground playground '<tr>';
            for(
    0spielfeld_x+= 1) {
                
    playground playground '<td></td>';
            }
            
    playground playground '</tr>';
        }
        
    playground playground '</table>';
        
        $(
    '#playground').html(playground);
    }

    function 
    createSpielfeld() {

        
    //tdObjekt initalisieren
        
    var tdObject null;
        for(
    0spielfeld_y+= 1) {
            for(
    0spielfeld_x+= 1) {

                
    //Objekt holen
                
    tdObject getTdObject(yx);

                
    //Die X-Koordinate speichern
                
    tdObject.data('x'x);
                
    //Die Y-Koordinate speichern
                
    tdObject.data('y'y);
                
    //Die Numer (Anzahl der umliegenden Minen) speichern
                
    tdObject.data('number'spielfeld[y][x]);

                
    //Das "Verdeckt"-Bild einfügen
                
    tdObject.html('<img src="' HTTP '/image/minesweeper-verdeckt.png" />');

                
    //WICHTIG: Benötigt jQuery-RightClick-Plugin
                //Funktioniert nicht auf allen Browsern (Opera)
                
    tdObject.rightClick(function (){
                    
    //Wenn noch nicht auf das Feld geklickt wurde
                    
    if ($(this).data('clicked') !== true) {
                        
    //Ein FlaggenBild setzen
                        
    $(this).html('<img src="' HTTP '/image/minesweeper-flagge.png" />');
                    }
                });

                
    //Wenn an dieser Position eine Mine liegt, ...
                
    if (spielfeld[y][x] === -1){
                    
    //... dann wird bei einem Klick ...
                    
    tdObject.click(function (){
                        
    //... das Minenbild angezeigt ...
                        
    $(this).html('<img src="' HTTP '/image/minesweeper-mine.png" />');
                        
    //.. und ausgegben, dass man verloren hat
                        
    alert('Sie haben verloren.');
                    });
                } else { 
    //Wenn an der Position keine Mine liegt
                    
    tdObject.click(function (){

                        
    //Speichern, dass auf dieses Feld schonmal geklickt wurde
                        
    $(this).data('clicked'true);

                        
    //Wenn es eine Feld ist, wo keine Minen im Umkreis sind
                        
    if ($(this).data('number') === 0) {
                            
    //Das Feld leeren
                            
    $(this).html('');

                            
    //Und die umliegenden Felder aufdecken
                            
    popupBlank($(this).data('y'), $(this).data('x'));

                            
    //Zum nächsten Schleifendurchlauf springen
                            
    return;
                        }

                        
    //In das aktuelle Feld die Minen-Anzahl reinschreiben
                        
    $(this).html($(this).data('number'));
                    });
                }
            }
        }


    Grüße

  • ByStones
    antwortet
    Über das Closure-Prinzip.
    Wie genau meinst du das ?

    Ich hab das ganze bis jetzt auf meinem FF getestet und da hat alles funktioniert ^^

    Einen Kommentar schreiben:


  • Chriz
    antwortet
    Funktioniert die Erzeugung eines konsistenten Spielfelds denn schon?

    Einen Kommentar schreiben:


  • nikosch
    antwortet
    Über das Closure-Prinzip.

    Einen Kommentar schreiben:


  • ByStones
    antwortet
    Noch eine ganz wichtig Fragen: Wenn ich in einer Funktion drin bin, z.b. $().each(function() { hier }), dann kann ich mit this ja nichtmehr auf das Objekt zugreifen, wie komme ich trotzdem dann das Objekt hin ?

    Einen Kommentar schreiben:


  • ByStones
    antwortet
    Sodele, ich hab das mal umgebaut:

    PHP-Code:
    $.widget("ui.minesweeper", {
        
    // default options
        
    options: {
            
    playground: new Array(),
            
    sizeX9,
            
    sizeY9,
            
    mines10,
            
    lostfalse,
            
    httpBase'.'
        
    },

        
    positionArray: [
        {
            
    y: -1,
            
    x1
        
    }, {
            
    y: -1,
            
    x0
        
    }, {
            
    y: -1,
            
    x: -1
        
    }, {
            
    y0,
            
    x: -1
        
    },
        {
            
    y0,
            
    x1
        
    }, {
            
    y1,
            
    x1
        
    }, {
            
    y1,
            
    x0
        
    }, {
            
    y1,
            
    x: -1
        
    }
        ],

        
    _create: function() {        
            
    //Spielfeld erzeugen
            
    for(var 0this.options.sizeY+= 1) {
                
    this.options.playground[y] = new Array();
                for(var 
    0this.options.sizeX+= 1) {
                    
    this.options.playground[y][x] = null;
                }
            }

            return 
    this;
        },

        
    _spreadMines: function (){
            
    //Aktuelle Anzahl der Minen
            
    var counter 1;
            do {
                
    //Zufällige X- und Y-Kooredinate für die Mine suchen
                
    Math.round(Math.random() * (this.options.playground[0].length 1));
                
    Math.round(Math.random() * (this.options.playground.length 1));

                
    //Wenn sich dort noch keine Mine befindet
                
    if (this.options.playground[y][x] !== -1) {
                    
    //Mine setzten
                    
    this.options.playground[y][x] = -1;

                    
    //Minenzähler erhöhen
                    
    counter += 1;
                }
            
    //Solange bis alle Minen verteilt sind
            
    } while (counter <= this.mines);

            return 
    this;
        },

        
    _spreadNumbers: function (){
            
    //Anzahl der umliegenden Minen der aktuellen Position
            
    var minenAround 0;

            
    //Jedes Feld in einer Schleife durchlaufen
            
    $(this.options.playground).each(function (i1y){
                $(
    y).each(function (i2x) {

                    
    //Wenn an dieser Position eine Mine ist, dieses Feld überspringen
                    //und mein nächsten Weitermachen
                    
    if (this.options.playground[i1][i2] == -1) {
                        return;
                    }

                    
    //Die umliegenden Minen auf 0 setzten
                    
    minesAround 0;

                    
    //Das Hilfsarray durchlaufen
                    
    $(this.positionArray).each(function (kval){
                        
    //Wenn die Position existiert...
                        
    if (array_key_exists(i1 val.ythis.options.playground)
                            && 
    array_key_exists(i2 val.xthis.options.playground[i1 val.y])
                            
    //... und auf dieser Postion eine Mine liegt...
                            
    && this.options.playground[i1 val.y][i2 val.x] == -1) {
                            
    //...den Minenzähler erhöhen
                            
    minesAround += 1;
                        }

                    });

                    
    //Die umliegenden Minen ins Array Schreiben
                    
    this.options.playground[i1][i2] = minesAround;

                });
            });

            return 
    this;
        },

        
    _getTdObject: function (i1i2) {
            
    //Das td-Objekt der Tabelle auf Basis der Koordinaten zurückgeben
            //Die + 1 deshalb bei :nth-child nicht mit 0 anfängt, sondern mit 1
            
    return $('.spielfeld tr:nth-child(' + (i1 1) + ') td:nth-child(' + (i2 1) + ')');
        },

        
    _checkClicked: function (i1i2) {
            
    //Wurde auf das Spielfeld schoneinmal geklickt
            
    return this._getTdObject(i1i2).data('clicked') === true;
        },

        
    _popupBlank: function (i1i2) {
            
    //Das Hilfsarray durchlaufen
            
    $(this.positionArray).each(function (keyval){
                
    //Wenn die entsprechende Position existiert ...
                
    if (array_key_exists(i1 val.ythis.options.playground)
                    && 
    array_key_exists(i2 val.xthis.options.playground[i1 val.y])
                    
    //... und noch nicht darauf geklickt wurde
                    //(Klick abfrage ist wichtig, sonst gibt es eine Endlosschleife) ...
                    
    && !this._checkClicked(i1 val.yi2 val.x)) {
                    
    //... einen Klick darauf ausführen
                    
    this._getTdObject(i1 val.yi2 val.x).click();
                }

            });
        },

        
    _renderPlayground: function () {
            
    //Spielfeld erstellen
            
    var playground '<table class="spielfeld">';
            for(
    0this.options.sizeY+= 1) {
                
    playground playground '<tr>';
                for(
    0this.options.sizeX+= 1) {
                    
    playground playground '<td></td>';
                }
                
    playground playground '</tr>';
            }
            
    playground playground '</table>';

            $(
    '#playground').html(playground);
        },

        
    _uncoverPlayground: function () {
            var 
    tdObject null;

            
    //Geht alle Felder durch
            
    for(0this.options.sizeY+= 1) {
                for(
    0this.options.sizeX+= 1) {

                    
    //Objekt holen
                    
    tdObject this._getTdObject(yx);

                    
    //Wenn auf dieses Feld noch nicht geklickt wurde
                    
    if (tdObject.data('clicked') !== true) {
                        
    //Dann klicken
                        
    tdObject.click();
                    }
                }
            }
        },

        
    _createPlayground: function () {

            
    //tdObjekt initalisieren
            
    var tdObject null;
            for(
    0this.options.sizeY+= 1) {
                for(
    0this.options.sizeX+= 1) {

                    
    //Objekt holen
                    
    tdObject this._getTdObject(yx);

                    
    //Die X-Koordinate speichern
                    
    tdObject.data('x'x);
                    
    //Die Y-Koordinate speichern
                    
    tdObject.data('y'y);
                    
    //Die Numer (Anzahl der umliegenden Minen) speichern
                    
    tdObject.data('number'this.options.playground[y][x]);

                    
    //Das "Verdeckt"-Bild einfügen
                    
    tdObject.html('<img src="' HTTP '/image/minesweeper-verdeckt.png" />');

                    
    //WICHTIG: Benötigt jQuery-RightClick-Plugin
                    //Funktioniert nicht auf allen Browsern (Opera)
                    
    tdObject.rightClick(function (){
                        var 
    $this = $(this);
                        
    //Wenn noch nicht auf das Feld geklickt wurde
                        
    if ($this.data('clicked') !== true) {
                            
    //Ein FlaggenBild setzen
                            
    $this.html('<img src="' this.options.httpBase '/image/minesweeper-flagge.png" />');
                        }
                    });

                    
    //Wenn an dieser Position eine Mine liegt, ...
                    
    if (this.options.playground[y][x] === -1){
                        
    //... dann wird bei einem Klick ...
                        
    tdObject.click(function (){
                            var 
    $this = $(this);
                            
    //Speichern, dass hier schoneinmal geklickt wurde
                            
    $this.data('clicked'true);

                            
    //... das Minenbild angezeigt ...
                            
    $this.html('<img src="' this.options.httpBase '/image/minesweeper-mine.png" />');

                            
    //Falls man noch nicht verloren hat:
                            
    if (this.options.lost === false) {

                                
    //Speichern, dass man verloren hat
                                
    this.options.lost true;

                                
    //Das gesamte Spielfeld aufdecken
                                
    this._uncoverPlayground();

                                
    //Die Verloren-Meldung ausgeben
                                
    alert('Sie haben verloren.');

                            }
                        });
                    } else { 
    //Wenn an der Position keine Mine liegt
                        
    tdObject.click(function (){
                            var 
    $this = $(this);

                            
    //Speichern, dass auf dieses Feld schonmal geklickt wurde
                            
    $this.data('clicked'true);

                            
    //Wenn es eine Feld ist, wo keine Minen im Umkreis sind
                            
    if ($this.data('number') === 0) {
                                
    //Das Feld leeren
                                
    $this.html('');

                                
    //Und die umliegenden Felder aufdecken
                                
    this._popupBlank($this.data('y'), $this.data('x'));

                                
    //Zum nächsten Schleifendurchlauf springen
                                
    return;
                            }

                            
    //In das aktuelle Feld die Minen-Anzahl reinschreiben
                            
    $this.html($this.data('number'));
                        });
                    }
                }
            }

        },
       
        
    destroy: function() {
            
    //Widget zerstören
            
    $.Widget.prototype.destroy.apply(thisarguments);
        }
    }); 
    Kann mir jemand sagen wie ich das ganz testen kann (einach jQuery UI + Minesweeper und fertig ?) ?

    Grüße

    Einen Kommentar schreiben:


  • rudygotya
    antwortet
    Du bräuchtest dann widget und core (evtl auch ui.mouse).

    Einen Kommentar schreiben:


  • ByStones
    antwortet
    Wenn ich das ganz nicht als jQuery-Plugin mache sondern als eigenes Objekt ?
    Und man das ganze dann so aufruft:
    PHP-Code:
    var mine = new Minesweeper();
    mine.options({
        
    sizeX50
    });

    mine.render($('.spielfeld')); 
    Wäre das dann besser, weil dann wär das ganz ja nicht in jQuery eingebaut, sondern eigenständig ?

    Edit: Während des Schreibens kam der jQuery UI Beitrag, dann hab ich dazu noch ne Frage: Wenn ich das als Widget machen will, muss man dann das jQuery UI einbinden, damit es funktionsfähig ist ?

    Einen Kommentar schreiben:


  • rudygotya
    antwortet
    Die Erzeugung des Spielfeldes ist mMn. dennoch ein super Anwendungsfall für ein Widget. Das hat aber nichts mit der Anwendung als Ganzes zu tun.

    Siehe auch jqueryui developer guide. Wenn man in dem hier besprochenen Fall das Spiel in verschiedenen Schwierigkeitsstufen anbieten möchte, ist das doch eine super Lösung.

    Einen Kommentar schreiben:


  • Manko10
    antwortet
    Ich würde generell keine eigenen Anwendungen als Plugins organisieren. Programme, die eigenständig Aufgaben erledigen und für einen bestimmten Zweck gemacht sind, sind eben eigenständige Anwendungen und keine Plugin-ins. Das Framework ist der Anwendung unterzuordnen, nicht umgekehrt. Ein Plugin ist jedoch dem Framework untergeordnet.

    Einen Kommentar schreiben:


  • rudygotya
    antwortet
    Wäre das dso richtig ?
    Nein, du gibst default Options vor und extendest dann mit den Optionen, die das widget dann bekäme. Hier mal ein einfaches Beispiel:
    PHP-Code:
    (function($) {
        
    /**
         * @desc: hide element elegant by using opacity;
         */
        
    $.fn.animOut = function (options) {
            var 
    opts = $.extend({}, $.fn.animOut.defaultsoptions);
            return 
    this.each(function(options) {
                var 
    $this = $(this),
                    
    = $.metadata ? $.extend({}, opts$this.metadata()) : opts;
                
    o.init.call(this);
                if($.
    browser.msie) {
                    
    $this.fadeOut(o.duration);
                } else {
                    
    $this.animate({
                        
    height'hide',
                        
    opacityo.opacity
                    
    }, o.duration);
                }
                if(
    o.hide) {
                    
    $this.hide();
                }
                
    o.callback.call(this);
            });
        };
        $.
    fn.animOut.defaults = {
            
    init : function(){},
            
    callback : function(){},
            
    opacity70,
            
    duration250,
            
    hidefalse
        
    };
    })(
    jQuery); 
    Edit: dem $ selector solltes tdu dann noch den Selector mitgeben, wohin denn gerendert werden soll.

    Einen Kommentar schreiben:


  • ByStones
    antwortet
    Zitat von rudygotya Beitrag anzeigen
    Toll finde ich, dass du so viel kommentierst. Super wäre es, wenn du bei so was evtl einen kurzen Beispiellink mit posten könntest, dass man den Code auch mal in Action sieht.
    Naja, zugegeben, normalerweise kommentiere ich nicht so viel, aber das man es schnell versteht, wenn es jemand hier liest hab ich einfach alles kommentiert.

    Zitat von rudygotya Beitrag anzeigen
    Paar kurze Tipps:
    Referenzier einmal am Anfang auf $(this), so erstellst du nicht jedes mal ein neues Objekt. Am Anfang jeder Funktion, die öfter darauf zugreift, dazu z.b. var $this = $(this); schreiben.
    Ok danke für den Tipp, das hab ich mal soweit umgebaut (wo man $(this) mehr als einmal benutzt).

    Zitat von rudygotya Beitrag anzeigen
    Eigentlich vermisse nur die Möglichkeit, dem Ganzen ein Options-Object geben zu können. jQuery.extend ist da sehr praktisch.
    PHP-Code:
    $.fn.extend({
    Minesweeper: {
    render: function(){ .... }
    }
    });

    $().
    Minesweeper.render() 
    Wäre das dso richtig ?

    Extensions erweitern in meinen Augen den Funktionsraum von jQuery. Sie sind hinreichend abstrakt oder konfigurierbar gestaltet, dass man sie für Individualanwendungen kombiniert einsetzen kann. Ein Spiel ist in sich komplett und gehört da IMHO nicht rein.
    Wie könnte man es dann machen ?

    Grüße

    Einen Kommentar schreiben:


  • rudygotya
    antwortet
    Ist die Frage, wo man die Grenze zieht. Für ein (Ui-)Widget spricht, dass er eine klar definierte Aufgabe hat, aber das ganze in den Ausmessungen/Spieloptionen variieren möchte. Die Erzeugung des Spielfelds sowie das zur Verfügung stellen von Callbacks und Events würde da schon sehr gut in ein Widget passen.
    Was das Auswerten des Spielergebnisses betrifft, bin ich dann wieder deiner Meinung, das hat im Widget nichts/nur sehr bedingt was zu suchen.

    Einen Kommentar schreiben:


  • nikosch
    antwortet
    Extensions erweitern in meinen Augen den Funktionsraum von jQuery. Sie sind hinreichend abstrakt oder konfigurierbar gestaltet, dass man sie für Individualanwendungen kombiniert einsetzen kann. Ein Spiel ist in sich komplett und gehört da IMHO nicht rein.

    Einen Kommentar schreiben:


  • rudygotya
    antwortet
    Was spricht denn gegen ein Widget / eine Extension?

    Einen Kommentar schreiben:

Lädt...
X