Matthias Scharwies: Alternative zu eval() für arithmetische Berechnungen

0 52

Alternative zu eval() für arithmetische Berechnungen

Matthias Scharwies
  • javascript
  1. 0
    Gunnar Bittersmann
    1. 1
      Rolf b
      1. 1
        Felix Riesterer
        1. 1
          Gunnar Bittersmann
      2. 0
        Matthias Scharwies
        1. 2
          Rolf b
          • javascript
          • programmiertechnik
          1. 0
            Matthias Scharwies
            1. 0
              Rolf b
              1. 0
                Camping_RIDER
                • humor
                • menschelei
          2. 1
            1unitedpower
            1. 0
              Rolf b
              1. 0
                1unitedpower
                1. 0
                  Rolf b
                  1. 0
                    1unitedpower
        2. 0
          JürgenB
          1. 1
            Christian Kruse
            1. 0
              JürgenB
              1. 0
                Christian Kruse
  2. 0
    Tabellenkalk
    1. 0
      Gunnar Bittersmann
  3. 0
    pl
    1. 0
      Gunnar Bittersmann
    2. 0
      Rolf b
      1. 1
        pl
        • javascript
        • programmiertechnik
        1. 0
          TS
          1. -1
            pl
            1. 0
              TS
              1. 0
                Tabellenkalk
                1. 0
                  TS
              2. 0
                pl
                1. 0
                  TS
                  1. -2
                    pl
                    • javascript
                    • programmiertechnik
                    • zu diesem forum
                    1. 0
                      Gunnar Bittersmann
                      • zu diesem forum
  4. 1
    Matthias Apsel
    1. 0
      Matthias Scharwies
      1. 2
        JürgenB
      2. 0
        Rolf b
  5. 0
    TS
    • javascript
    • programmplanung
    1. 0

      Mathe-Quiz - Aufgabenstellung zusammengefasst

      Matthias Scharwies
      1. 0

        Mathe-Quiz - aufgabenstellung zusammengefasst

        Matthias Apsel
        1. 0
          dedlfix
          1. 0
            Matthias Apsel
          2. 0

            Mathe-Quiz - für welche Schüler?

            Matthias Scharwies
      2. 0

        Mathe-Quiz 0.3 (läuft)

        Matthias Scharwies
        1. 0
          TS
          1. 0
            Gunnar Bittersmann
            1. 0
              Tabellenkalk
              1. 0
                JürgenB
                1. 0
                  Gunnar Bittersmann
                2. 0
                  TS
        2. 0
          Tabellenkalk
          • javascript
          • programmplanung
          • rechnen

problematische Seite

Servus!

Ich versuche ein Mathe-Quiz zu programmieren.

In einem Menü mit radio-Buttons kann man den Operator auswählen. Eigentlich könnte man den gewählten Radiobutton ermitteln, dessen value (oder den Textinhalt des Labels) auslesen und mit Zufallszahlen in eine Zeichenkette umwandeln, die dann mit eval() ausgewertet wird.

var operator = document.querySelector('input[name="op"]:checked').value;
ergebnis = eval(zahl1 + operator + zahl2);   

Ich würde gerne auf eval() verzichten und habe nun ein Monster erschaffen:

    var operator = document.querySelector('input[name="op"]:checked').id;
    switch (operator) {
    case 'plus':
	  ergebnis = zahl1 + zahl2;
	  document.querySelector('#operator').textContent = '+';	
    break;
    case 'minus':
	  ergebnis = zahl1 - zahl2;
	  document.querySelector('#operator').textContent = '-';	
    break;
    case 'div':
	  ergebnis = zahl1 / zahl2;
	  document.querySelector('#operator').textContent = ':';		  
    break;
    case 'mal':
	  ergebnis = zahl1 * zahl2;
	  document.querySelector('#operator').textContent = '*';	
    break;
    case 'random':
	  document.querySelector('output').textContent = 'Was soll ich hier machen?';
	  document.querySelector('#operator').textContent = '?';	  
    break;
    default:
      document.querySelector('output').textContent ='Sie bleiben leider dumm!';
    break;
    }

Trotzdem (oder gerade deshalb) stehe ich auf dem Schlauch, wie ich im Falle der Zufallsauswahl "random" den Operator zufällig ermittele (evtl operator = rand(1,4); ) und dann ohne weiteren verschachtelten switch wieder in die Rechnungen einfüge.

Über Ideen und Lösungsansätze wäre ich sehr dankbar.

Herzliche Grüße

Matthias Scharwies

--
Es gibt viel zu tun: ToDo-Liste

akzeptierte Antworten

  1. problematische Seite

    @@Matthias Scharwies

    Trotzdem (oder gerade deshalb) stehe ich auf dem Schlauch, wie ich im Falle der Zufallsauswahl "random" den Operator zufällig ermittele (evtl operator = rand(1,4); ) und dann ohne weiteren verschachtelten switch wieder in die Rechnungen einfüge.

    Die möglichen Operatoren in einem Array speichern?

    var operators = ['plus', 'minus', 'div', 'mal'];
    

    Vor dem switch dann:

    if (operator == 'random')
    {
    	operator = operators[Math.floor(4 * Math.random())];
    }
    
    

    Wobei man das auch zusammenfassen könnte:

    if (operator == 'random')
    {
    	operator = ['plus', 'minus', 'div', 'mal'][Math.floor(4 * Math.random())];
    }
    
    

    LLAP 🖖

    “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory

    1. problematische Seite

      Die möglichen Operatoren in einem Array speichern?

      var operators = ['plus', 'minus', 'div', 'mal'];
      

      Das, und dazu noch die Operatoren in einem OBJEKT speichern und Methoden zuordnen? Ich verwende mal nur "klassische" Syntax. Alle Methoden tun das gleiche: sie bekommen a und b und liefern ein Objekt zurück, in dem das darzustellende Symbol und das erwartete Ergebnis stehen.

      var randomOps = [ 'plus', 'minus', 'mal', 'div' ];
      var opMap = {
         'plus': function(a,b) { return { symbol: '+', erwartet: a+b; } },
         'minus': function(a,b) { return { symbol: '-', erwartet: a-b; } },
         'mal': function(a,b) { return { symbol: '*', erwartet: a*b; } },
         'div': function(a,b) { return { symbol: '/', erwartet: a/b; } },
         'random': function(a,b) {
                      var op = rand(0, randomOps.length);
                      return opMap[randomOps[op]](a,b);
                   }
      };
      
      var a = rand(1,9), 
          b = rand(1,9),
          operator = document.querySelector('input[name="op"]:checked').id,
          handler = opMap[operator];
      
      if (!handler) { /* Error */ }
         
      var opInfo = handler(a,b);
      document.querySelector('#operator').textContent = opInfo.symbol;
      ergebnis = opInfo.erwartet;
      

      Auf diese Weise holt man sich direkt die Auswertefunktion aus dem Dictionary und braucht keinen Switch mehr. Random ist auch nur eine Funktion, die sich einfach der anderen Dictionary-Einträge bedient.

      Zu abstrakt? Oder ok?

      Rolf

      1. problematische Seite

        Lieber Rolf,

        var randomOps = [ 'plus', 'minus', 'mal', 'div' ];
        

        ginge das denn nicht auch mit Object.keys(), also opMap.keys()? Damit spart man sich ein unnötiges Array.

        var opMap = {
           'random': function(a,b) {
                        var op = rand(0, randomOps.length);
                        return opMap[randomOps[op]](a,b);
                     }
        };
        

        Vielleicht eher so?

        "random": function (a, b) {
            var keys = opMap.keys();
            return opMap[keys[rand(0, keys.length)]](a, b);
        }
        

        Noch schöner fände ich ja, wenn man die richtigen Taschenrechnerzeichen benutzte und sämtliche Bezeichner in rein englischer Sprache formulierte (das Internet ist international und englisch die lingua franca):

        var opMap = {
            "add": function(a, b) {
                return { symbol: "+", result: a+b };
            },
            "substract": function(a, b) {
                return { symbol: "-", result: a-b };
            },
            "multiply": function(a, b) {
                return { symbol: "×", result: a*b };
            },
            "divide": function(a, b) {
                return { symbol: "÷", result: a/b };
            },
            "any": function(a, b) {
                var keys = opMap.keys();
                return opMap[keys[rand(0, keys.length)]](a, b);
            }
        };
        
        var opInfo = handler(a,b);
        document.querySelector('#operator').textContent = opInfo.symbol;
        ergebnis = opInfo.erwartet;
        

        Das müsste man dann noch so anpassen:

        var opInfo = handler(a,b);
        document.querySelector('#operator').textContent = opInfo.symbol;
        ergebnis = opInfo.result;
        

        Liebe Grüße,

        Felix Riesterer.

        1. problematische Seite

          @@Felix Riesterer

          Noch schöner fände ich ja, wenn man die richtigen Taschenrechnerzeichen benutzte

          Ja, aber bitte konsequent. '-' U+002D ist kein Minuszeichen; '−' U+2212 ist eins.

          Der Unterschied ist deutlich zu sehen:

          Screenshot

          und sämtliche Bezeichner in rein englischer Sprache formulierte

          Warum nicht die Symbole '+', '−', '×', '÷'?

          Oder '➕' U+2795, '➖' U+2796, '✖️' U+2716, '➗' U+2797?

          LLAP 🖖

          --
          “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
      2. problematische Seite

        Guten Morgen!

        Vielen Dank für Eure wertvollen Lösungen. Ich habe sie schon umgesetzt.

        @Rolf b Danke, das mit dem Objekt ist die eleganteste und beste Lösung!

        @Felix Riesterer Ja, die Variablennamen und Funktionen sollten englische (und sprechende) Namen haben.


        Jetzt muss ich noch ein bisschen hirnen:

        • Bei Substraktionen sollte die zweite Zahl niedriger als die erste sein, um kein negatives Ergebnis zu haben.
        • Bei Divisionen sollt das Ergebnis ganzzahlig sein.

        Also muss ich die Zufallszahlen a und b wohl in das Objekt integrieren.

        • Das Entersymbol ↵ im submit-Button wird auf meinem Tablet nicht angezeigt, da muss ich etwas anderes aussuchen.

        Herzliche Grüße

        Matthias Scharwies

        --
        Es gibt viel zu tun: ToDo-Liste
        1. problematische Seite

          Die mathematische Operation Substraktion kenne ich nicht - ist das Rechnen mit Teilstrings? ;-)

          Um die gewünschten Ergebniseigenschaften zu erhalten, wirst Du bei Disvision und Substraktion nicht a und b zufällig bestimmen müssen, sondern b und erwartet, und a daraus rückrechnen. D.h. dein Rückgabeobjekt muss erweitert werden, so dass es auch die Operanden enthält. Ob du die rand() Aufrufe dann auch in die Methoden verlegst, oder ob Du a und b nach wie vor übergibst, ist wohl Geschmackssache

          Den Ansatz mit opMap.keys() hatte ich zuerst auch (naja, eigentlich nicht, ich war auf getOwnPropertyNames verfallen, was in diesem Fall zum gleichen Ergebnis geführt hätte; aber keys() ist natürlich sinnvoller). Problem ist nur, dass opMap.keys() auch 'random' enthält, d.h. man läuft Gefahr, dass die Random-Operation sich selbst auswählt. Die Chance dafür ist natürlich gering ($$(\frac{1}{5})^k$$ für k-mal nacheinander), aber es widerstrebt mir irgendwie, korrekte Programmfunktion auf Wahrscheinlichkeiten aufzubauen bzw. eine unabsichtliche Rekursion einfach hinzunehmen. Das unit-testet sich so schlecht...

          Eine Sache ist mir erst nachträglich aufgefallen: Es ist schlechter Stil, vielleicht sogar ein Bug, dass die Methoden in opMap sich auf die Variable beziehen, in der ihr Objekt gespeichert ist. Statt dessen sollten sie this verwenden.

          Rolf

          1. problematische Seite

            Servus!

            Die mathematische Operation Substraktion kenne ich nicht - ist das Rechnen mit Teilstrings? ;-)

            Oops - wird heut noch geändert!

            Um die gewünschten Ergebniseigenschaften zu erhalten, wirst Du bei Division und Subtraktion nicht a und b zufällig bestimmen müssen, sondern b und erwartet, und a daraus rückrechnen.

            Ja, da werd' ich mich am Wochenende dran machen.

            Vielen Dank!

            Rolf

            Herzliche Grüße

            Matthias Scharwies

            --
            Es gibt viel zu tun: ToDo-Liste
            1. problematische Seite

              Du hast noch einen Pösen Pug drin, den Du zu Poden chleudern musst.

              In der task() Funktion registierst Du einen submit-Handler, wertest darin die Antwort aus und startest dann nach 1s nochmal task(). Hier wird wieder ein submit-Handler registriert, der die Antwort... usw.

              Ich hatte mich gewundert, warum nach ein paar Fragen ein Spielautomat-Effekt bei den Aufgabenzahlen auftrat. Grund war, dass ca 50 Eventhandler aktiv waren und jeder eine neue Aufgabe stellen wollte.

              Problem: Du registrierst eine inline-Funktion als submit-Handler. Das ist jedesmal ein neues Function-Objekt, oder zumindest bildet es eine neue Closure um den Aufrufkontext von task(), und darum wird jedesmal neu registriert.

              Lösung 1: Irgendwie erkennen, dass schon registriert ist und es nur beim ersten Mal tun. Das erste Mal ist eh am schönsten.

              Lösung 2: Keine inline-Funktion verwenden, sondern eine eigene Funktion evaluateResponse(evt), die außerhalb von task() definiert ist. Sie hat dann trotzdem Zugriff auf die Closure des ready-Handlers, und das reicht. Ich habe mir deine HTML Seite mal lokal kopiert und diese Lösung probiert - zumindest Chrome erkennt dann, dass er diesen Handler schon hat, und registriert ihn nicht nochmal.

              evaluateResponse innerhalb von task() als eigene Funktion zu definieren funktioniert dagegen nicht. Auch hier würde jedesmal eine neue Closure gebildet und ein neuer submit-Handler registriert.

              Rolf

              1. problematische Seite

                Aloha ;)

                Du hast noch einen Pösen Pug drin, den Du zu Poden chleudern musst.

                Du hast nicht zufällig einen gewissen Jugendfreund namens Schwanzus Longus?

                Grüße,

                RIDER

                --
                Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
          2. problematische Seite

            Eine Sache ist mir erst nachträglich aufgefallen: Es ist schlechter Stil, vielleicht sogar ein Bug, dass die Methoden in opMap sich auf die Variable beziehen, in der ihr Objekt gespeichert ist. Statt dessen sollten sie this verwenden.

            Das ist kein Fehler, das ist ein rekursiver Closure und in JavaScript durchaus auch üblich. Das ist sogar der bessere Stil, weil es besser vorherzusehen ist, wie sich so ein Programm verhält. Wir können ja mal ein kurzes Experiment starten: Was ist wohl die Ausgabe des folgenden Codes (die Lösung ganz am Ende des Posts)

            const math = {
              fac(x) {
                return (x > 1)
                  ? x * math.fac(x - 1)
                  : 1;
              }
            };
            
            math.fac(1);
            math.fac(3);
            math.fac(5);
            math.fac.call({fac(){return 170}}, 1);
            math.fac.call({fac(){return 170}}, 3);
            math.fac.call({fac(){return -35}}, 3);
            math.fac.call({fac(){return NaN}}, 5);
            math.fac.call(null, 5);
            

            Und was wäre die Ausgabe, wenn math.fac intern this verwenden würde? Also wie folgt definiert wäre:

            const math = {
              fac(x) {
                return (x > 1)
                  ? x * this.fac(x - 1)
                  : 1;
              }
            };
            
            Lösung:
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            Ohne this: 1, 6, 120, 1, 6,   6   , 120, 120
            Mit this:  1, 6, 120, 1, 510, -105, NaN, Type Error
            

            Bei der ersten Variante hängt das Verhalten nicht vom Aufruf der Funktion ab, sondern ausschließlich von ihrer Definition. Im zweiten Fall hängt das Verhalten von der Definition und dem Aufruf der Funktion ab. Es kommt also eine Laufzeit-Abhängigkeit ins Spiel und das macht es schwierig den Code zu verstehen.

            1. problematische Seite

              Nach dieser Argumentation muss man this immer vermeiden, weil call und apply ein "fremdes" this injizieren können. Was OOP in Javascript ziemlich umständlich macht.

              Ein fremdes this injiziert man mMn nur in Funktionen, die darauf ausgelegt sind, per this einen Kontext vorgegeben zu bekommen (Eventhandler in jQuery zum Beispiel). Objektmethoden sind darauf typischerweise nicht ausgelegt. Wenn man es doch tut, ist es halt GIGO[1].

              Es bleibt trotzdem schlechter Stil, wenn die Methoden eines Objekts wissen, in welcher Variablen das Objekt gespeichert ist. Eine Lösung ohne this, die etwas taugt, müsste das Module-Pattern verwenden:

              var opMap = (function() {
                 var ops = {
                     add(a,b) { return { symbol:"+", erwartet:a*b}; },
                     sub(a,b) { return {...}; },
                     mul(a,b) { { return {...}; },
                     div(a,b) { { return {...}; }
                 };
              
                 return {
                    add(a,b) { return ops.add(a,b); },
                    sub(a,b) { return ops.sub(a,b); },
                    mul(a,b) { return ops.mul(a,b); },
                    div(a,b) { return ops.div(a,b); },
                    any(a,b) { /* einen Key aus ops.keys() auswählen und ops[key](a,b) aufrufen */ }
                 };
              })();
              

              Das ist dann so etwas wie Selbstverteidigung gegen bösartige this-Injizierer. Aber wenn ich Krieg der Kerne spielen will, besorge ich mir doch lieber eine MARS Umgebung. Aus jeder Klasse ein Modul zu machen kann arg in Boilerplate-Arbeit ausarten.

              Rolf


              1. Garbage In - Garbage Out ↩︎

              1. problematische Seite

                Es bleibt trotzdem schlechter Stil, wenn die Methoden eines Objekts wissen, in welcher Variablen das Objekt gespeichert ist.

                Ist es möglich, dass du die Vor- und Nachteile der statischen und dynamischen Lösung gerade miteinander vertauschst? Der Vorteil der statischen Variante ist ja gerade, dass man überhaupt keine zusätzlichen Annahmen über den Ausführungskontext treffen muss. Natürlich, die Methode muss in diesem Fall die Variable math kennen, aber das tut sie, weil sie in der selben lexikalischen Umgebung liegt. Die Funktion kennt math auf jeden Fall, ob man das nun nutzt oder nicht.

                Bei der dynamischen Variante dagegen, hängt die Auswertung der Funktion von viel mehr Einflussfaktoren ab. Zunächst mal zählen auch alle statischen Gültigkeitsregeln dazu, denn die lassen sich nicht deaktivieren, die gelten so oder so. Aber im dynamischen Fall kommt da eben nochmal ein kompletter Laufzeitkontext oben drauf. Das heißt, der er oder die Entwickler(in) muss nun Kopfrechnen und verschiene Kontrollflüsse durchspielen. Ist das synchron oder asynchron? In welcher Reihenfolge werden diese Statements abgespielt? Welchen Werte kann diese oder jene Variable zur Laufzeit annehmen? Zusätzlich zu den statischen Eigenschaften muss man also eine ganze Menge dynamischer Eigenschaften prüfen.

                Das klingt sehr theoretisch, aber es ist ein wahrer Augenöffner zu erfahren, welche Auswirkungen das auf das menschliche Gehirn hat: Der Mensch ist von Natur aus sehr begabt bei der Musterekennung, das hilft uns dabei gefährliche Tiere im Wald zu entdecken, essbare von giftigen Beeren zu unterscheiden oder eine Beute zu verfolgen. Aber genau diese Fähigkeit hilft uns auch beim gedanklichen Parsen von Quelltexten und dabei statische Programmeigenschaften in Rekord-Geschwindigkeit zu erfassen.

                Wir sind aber von Natur aus unbegabt darin Alternativen gegeneinader abzuwägen. Ein Schachmeister kann vielleicht 8 bis 10 Züge mit allen Alternativen vorausdenken. und genau das ist die Fähigkeit, die wir bräuchten um dynamische Programmeigenschaften zu evaluieren. Wir sind also kognitiver viel stärker belastet, wenn wir Laufzeitkontexte berücksichtigen müssen.

                Die Konsequenz daraus ist, dass wir uns die Bedeutung statischer Lösungen zu Programmierprobelmen schneller erschließen können als deren dynamische Pendants. Das zu verdeutlichen war Zweck meines Experiments.

                1. problematische Seite

                  D.h. du siehst dieses Objekt als JavaScript-Implementierung einer Klasse mit statischen Methoden. Da viele Programmiersprachen keine Metaklassen kennen, gibt es in ihnen keine Möglichkeit, dass statische Methoden ihre Klasse abstrakt ansprechen. Deswegen ist es dort üblich, dass statische Methoden auf andere statische Methoden der gleichen Klasse direkt zugreifen.

                  Wenn man das aber nicht MUSS, dann sollte man es auch nicht.

                  JavaScript hat noch das besondere "Feature", einer Funktion ein beliebiges this unterschieben zu können, und hindert mich auch nicht daran, das bei Methodenaufrufen zu tun. Wie schon geschrieben - ich halte den Einsatz dieser Technik bei METHODEN für falsch. In einer Methode habe ich eine definitive Erwartung, welchen Wert this hat. Bei freien FUNKTIONEN ist das was anderes. Deswegen halte ich dein Argument, dass der Gebrauch von this in einer Methode riskant ist, für irreführend.

                  Und dann bin ich mit deiner Deutung von "kennen" nicht glücklich. Dass die Methoden des opMap-Objekts die Variable "opMap" sehen, weil sie im gleichen Kontext liegen, heißt ja noch nicht, dass sie sie auch benutzen sollten. Ich muss nicht alles anfassen, was ich sehe - als kleiner Junge habe ich das schmerzhaft gelernt (Kochtopf). Es gibt Dinge, die fasst man besser nicht an. Objekte sollten nicht eigenständig aus sich hinausgreifen. Wenn sie was brauchen, muss man es ihnen liefern. Alles andere führt zu langfaserigem Objektfilz.

                  Ja, du hast recht, statischer Code ist - solange er nicht zu groß wird - einfacher zu erfassen. Wird er größer, entstehen viel zu viele Abhängigkeiten und nicht mehr wartbares Chaos. Das ist für Matthias' kleinen Rechner nicht das Problem. Aber wenn man die entsprechenden Programmiermuster im Kleinen einübt, muss man sich bei größeren Projekten nicht erst neu dran gewöhnen.

                  Auch das ist eine Eigenschaft von Menschen: Wir sind Gewohnheitstiere. Gewohnheiten zu meiden, die sich als schädlich herausstellen können, ist daher eine nützliche Sache. Dass ich die Hand auf den Herd legen kann, wenn er kalt ist, ist zwar ungefährlich, aber trotzdem habe ich mir angewöhnt, das sein zu lassen. Weil heiß sein kann.

                  Rolf

                  1. problematische Seite

                    D.h. du siehst dieses Objekt als JavaScript-Implementierung einer Klasse mit statischen Methoden.

                    Nein, so sehe ich es nicht. Dynamisch bedeutet bloß, dass ein Stück Code von der Laufzeit abhängig ist. Es verhält sich immer angepasst an die Situation. Statisch bedeutet, dass ein Stück Code unabhängig von der Laufzeit ist. Es verhält sich immer gleich, es lässt sich vorhersehen was passiert, indem man einfach nur einen Blick auf die Definition wirft.

                    Mit "abstrakten Metaklassen" habe ich das nicht in Verbindung bringen wollen. Darunter kann ich mir auch nicht viel vorstellen.

                    JavaScript hat noch das besondere "Feature", einer Funktion ein beliebiges this unterschieben zu können, und hindert mich auch nicht daran, das bei Methodenaufrufen zu tun.

                    Das ist gerade das Schmutzige an der Sache. Es wird erst beim Aufruf der Methode entschieden, was this ist. Das ist in allen OOP-Sprachen so, nicht nur in JavaScript. Das ist der berühmte Gorilla mit der Banane, der im Dschungel steht.

                    “The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” – Joe Armstrong

                    In Matthias' Fall wäre opMap die Banane. Man kann direkt danach greifen. this dagegen ist die Banane, in der Hand des Gorillas und dazu der ganze Dschungel.

                    Und dann bin ich mit deiner Deutung von "kennen" nicht glücklich. Dass die Methoden des opMap-Objekts die Variable "opMap" sehen, weil sie im gleichen Kontext liegen, heißt ja noch nicht, dass sie sie auch benutzen sollten.

                    Wenn man versucht vorhersehbaren und leserlichen Code zu schreiben, dann sollte man das. Der lexikalische Scope bedeutet äußerst hohe Lokalität und Kohärenz.

                    Objekte sollten nicht eigenständig aus sich hinausgreifen. Wenn sie was brauchen, muss man es ihnen liefern. Alles andere führt zu langfaserigem Objektfilz.

                    Hier überschlägst du dich. Was verstehst du unter "hinausgreifen"? Ein Griff in die lexikalische Umgebung ist jedenfalls einem Griff in die Laufzeit-Umgebung vorzuziehen.

                    Ja, du hast recht, statischer Code ist - solange er nicht zu groß wird - einfacher zu erfassen. Wird er größer, entstehen viel zu viele Abhängigkeiten und nicht mehr wartbares Chaos.

                    Da sind meine Erfahrungen anders. Dynamischer Code ist im Kleinen schon schwierig zu verstehen und die Komplexität wächst über-proportional mit der Menge des Codes. Je mehr Laufzeitkontext man berücksichtigen muss, desto schwieriger wird es den Code zu verstehen. Der statische Ansatz reduziert Code-Abhängigkeiten um eine Vielfaches, indem Laufzeit-Abhängigkeiten kategorisch ausgeschlossen werden. Man gerät also gar nicht erst so schnell in die Dependency-Hell. Und noch was: In Sprachen ganz ohne dynamische Features, Haskell zum Beispiel, gibts gar keine andere Möglichkeiten als Abhängigkeiten per DI aufzulösen. Abhängigkeiten sind immer explizit, nie implizit.

                    Auch das ist eine Eigenschaft von Menschen: Wir sind Gewohnheitstiere. Gewohnheiten zu meiden, die sich als schädlich herausstellen können, ist daher eine nützliche Sache.

                    Da sind wir uns einig, und this ist in JavaScript bekannt für seine Fehleranfälligkiet und Unvorhersehbarkeit. Closures dagegen haben sich als zuverlässige Lösung etabliert.

        2. problematische Seite

          Hallo Matthias,

          du musst dich bei der Eingabe des Ergebnisses auch noch den Dezimaltrenner kümmern, 1,5 liefert ein falsch, 1.5 ein richtig.

          Ich prüfe nach dem einlesen auf isNaN und ersetze bei Bedarf das „,“ durch einen „.“.

          Aus meiner Wühlkiste:

            // Zahlen einlesen und bei Bedarf korrigieren
            var get_num = function(e) {
              var num = e.value;
              if (isNaN(num)) { num = num.replace(/,/g,"."); }
              if (isNaN(num) || num.length==0 ) { num = 0.0; e.value = num; }
              return parseFloat(num);
            }
          

          Gruß
          Jürgen

          1. problematische Seite

            Hallo JürgenB,

            du musst dich bei der Eingabe des Ergebnisses auch noch den Dezimaltrenner kümmern, 1,5 liefert ein falsch, 1.5 ein richtig.

            Sofern der richtige Feld-Typ genommen wird, ist das nicht nötig.

            Ich prüfe nach dem einlesen auf isNaN und ersetze bei Bedarf das „,“ durch einen „.“.

            <input type="number"> behandelt das transparent, siehe auch.

            LG,
            CK

            1. problematische Seite

              Hallo Christian,

              <input type="number"> behandelt das transparent, siehe auch.

              meine (schon etwas zurückliegenden) Tests haben leider ergeben, das die Erkennung des Dezimaltrenners nicht browserübergreifend funktioniert. Daher verwende ich den Test auch bei <input type="number">.

              Gruß
              Jürgen

              1. problematische Seite

                Hallo JürgenB,

                <input type="number"> behandelt das transparent, siehe auch.

                meine (schon etwas zurückliegenden) Tests haben leider ergeben, das die Erkennung des Dezimaltrenners nicht browserübergreifend funktioniert.

                Ja, das ist wohl leider so, vor allem unter den mobilen Browsern.

                Daher verwende ich den Test auch bei <input type="number">.

                Na, ich wills dir ja auch nicht ausreden. 😉

                LG,
                CK

  2. problematische Seite

    Hallo,

    Über Ideen und Lösungsansätze wäre ich sehr dankbar.

    den Random-Fall vor dem switch abhandeln und den Operator aus einem geshuffleten Array ziehen und damit dann in den Switch gehen?

    Gruß
    Kalk

    1. problematische Seite

      @@Tabellenkalk

      den Operator aus einem geshuffleten Array ziehen

      AFAIS gibt’s in JavaScript im Gegensatz zu PHP kein Array.shuffle().

      LLAP 🖖

      --
      “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
  3. problematische Seite

    Hab ich auch mal programmiert sowas. Ohne eval: Sobald die Aufgabe gezeigt wird, steht das Ergebnis ja schon fest.

    1. problematische Seite

      @@pl

      Hab ich auch mal programmiert sowas. Ohne eval: Sobald die Aufgabe gezeigt wird, steht das Ergebnis ja schon fest.

      Was will uns der Künstler damit sagen?

      In anderen Worten: Ist das Kunst oder kann das weg?

      LLAP 🖖

      --
      “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
    2. problematische Seite

      Weniger provokant gefragt: wie hast Du - basierend auf dem ausgewählten Operator - das erwartete Ergebnis berechnet, wenn nicht mit eval()? Zwei Lösungen wurden hier diskutiert (Matthias' Monstrum und Rolfs Rechenobjekt), wie funktioniert Hottis Hexerei?

      Rolf

      1. problematische Seite

        Weniger provokant gefragt: wie hast Du - basierend auf dem ausgewählten Operator - das erwartete Ergebnis berechnet, wenn nicht mit eval()?

        Wie ich geschrieben habe. Zb so: if(operator == 'plus'){ x = a + b } dann wäre nur noch zu vergleichen ob der Anwender für x dasselbe rausgekriegt und als seine Lösung eingegeben hat. Die Kontrollstruktur auf die anderen Operatoren zu erweitern ist ja kein Problem und übersichtlich bleibt das auch.

        Problematisch könnte es bei einer Division werden, da muss es eine Vereinbarung geben bezüglich der Genauigkeit (Anzahl der Nachkommastellen).

        1. problematische Seite

          Hello,

          Wie ich geschrieben habe. Zb so: if(operator == 'plus'){ x = a + b } dann wäre nur noch zu vergleichen ob der Anwender für x dasselbe rausgekriegt und als seine Lösung eingegeben hat. Die Kontrollstruktur auf die anderen Operatoren zu erweitern ist ja kein Problem und übersichtlich bleibt das auch.

          Das sehe ich auch so. Die klassischen Lösungen sind mMn am verständlichsten, wartungsfreundlichsten und meistens auch ohne versteckte Fehlerquellen.

          Problematisch könnte es bei einer Division werden, da muss es eine Vereinbarung geben bezüglich der Genauigkeit (Anzahl der Nachkommastellen).

          Wieso Nachkommstellen?
          Die Operanden (der Dividend) werden vorher durch Multiplikation von Zufahlszahlen (Divisor * Quotient) ermittelt und deren Ergebnis ist immer ganzzahlig. Im Unterschied zum Schüler weiß der Lehrer (das Programm) die Lösung ja schon vorher.

          Liebe Grüße
          Tom S.

          --
          Es gibt nichts Gutes, außer man tut es
          Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
          1. problematische Seite

            Wieso Nachkommstellen?

            Eins durch drei gibt davon ziemlich viele...

            1. problematische Seite

              Hello,

              Wieso Nachkommstellen?

              Eins durch drei gibt davon ziemlich viele...

              Hast Du gelesen, was ich geschrieben habe?

              1 / 3 wird als Aufgabe nicht vorkommen, da bei der Ermittlung der Aufgabe zwei Ganzzahlen ausgewürfelt werden, die miteinander multipliziert werden. Und dann wird aus dem Produkt der Dividend.

              Den Punkt von oben muss ich Dir leider hier wieder wegnehmen :-O

              Liebe Grüße
              Tom S.

              --
              Es gibt nichts Gutes, außer man tut es
              Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
              1. problematische Seite

                Hallo,

                1 / 3 wird als Aufgabe nicht vorkommen,

                Also willst du im Quiz suggerieren, dass beim Dividieren der Integerbereich nicht verlassen wird?

                Gruß
                Kalk

                1. problematische Seite

                  Hello,

                  1 / 3 wird als Aufgabe nicht vorkommen,

                  Also willst du im Quiz suggerieren, dass beim Dividieren der Integerbereich nicht verlassen wird?

                  Darum fragte ich ja nach der genauen Aufgabenstellung.

                  Wenn die Schüler mit Rest arbeiten sollen, müssen die Eingabemöglichkeiten beim Ergebnis das auch hergeben.

                  Liebe Grüße
                  Tom S.

                  --
                  Es gibt nichts Gutes, außer man tut es
                  Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
              2. problematische Seite

                1 / 3 wird als Aufgabe nicht vorkommen,

                Elf durch fünf hab ich auf problematischer Seite schon gesehen. Acht durch sieben auch... und davon bin ich ausgegangen.

                1. problematische Seite

                  Hello,

                  1 / 3 wird als Aufgabe nicht vorkommen,

                  Elf durch fünf hab ich auf problematischer Seite schon gesehen. Acht durch sieben auch... und davon bin ich ausgegangen.

                  Darum ist die Seite doch "problematisch".
                  Matthias hat deutlich geschrieben, dass er noch über diese Teilaufgabe grübeln muss.

                  tztz

                  Liebe Grüße
                  Tom S.

                  --
                  Es gibt nichts Gutes, außer man tut es
                  Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
                  1. problematische Seite

                    Was ich gelesen habe:

                    Über Ideen und Lösungsansätze wäre ich sehr dankbar.

                    Hab daher meine Idee hier veröffentlicht. Statt Dankbarkeit kam eine besonders arrogante Antwort von einem Herrn Bittersmann, was allerdings wiederum typisch für dieses Forum ist.

                    Tom ich sag Dir was: Es macht keinen Spaß mehr hier. Aber vergraulen lasse ich mich deswegen noch lange nicht und schon gar nicht infolge heckenschützenartiger Bewertungen. Das ist einfach nur Dumm.

                    MfG

                    1. problematische Seite

                      @@pl

                      Über Ideen und Lösungsansätze wäre ich sehr dankbar.

                      Hab daher meine Idee hier veröffentlicht.

                      Nicht in dem Posting, auf das ich „besonders arrogant geantwortet“ hatte.

                      In jenem Posting hatte ich nicht nur keinen Lösungsansatz, sondern auch keine andere Idee gefunden. Das hab ich mit Humor genommen. Du offenbar nicht.

                      von einem Herrn Bittersmann, was allerdings wiederum typisch für dieses Forum ist.

                      Dass sich der Sinn deiner Postings hin und wieder nur dir selbst erschließt, ist auch typisch für dieses Forum.

                      Aber vergraulen lasse ich mich deswegen noch lange nicht

                      Das wäre auch schade. Dem Forum würde ein Unikum verlorengehen.

                      und schon gar nicht infolge heckenschützenartiger Bewertungen. Das ist einfach nur Dumm.

                      Zu auf dich zukommenenden Geschossen hatte dir JürgenB ja was gar nicht so Dummes nahegelegt.

                      LLAP 🖖

                      --
                      “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
  4. problematische Seite

    Hallo Matthias Scharwies,

    var operator = document.querySelector('input[name="op"]:checked').value;
    ergebnis = eval(zahl1 + operator + zahl2);
    

    Wenn du es so schreibst, ist ergebnis eine globale Variable.

    Ich würde gerne auf eval() verzichten

    Ist eval() nicht für genau solche Fälle gedacht!?

    Bis demnächst
    Matthias

    --
    Rosen sind rot.
    1. problematische Seite

      Servus!

      Hallo Matthias Scharwies,

      var operator = document.querySelector('input[name="op"]:checked').value;
      ergebnis = eval(zahl1 + operator + zahl2);
      

      Wenn du es so schreibst, ist ergebnis eine globale Variable.

      Wär' ja auch kein Problem, ich hatte eigentlich ziemlich viel globale Variablen am Anfang, die jetzt zum überwiegenden Teil in die task()-Funktion gewandert sind.

      Ich würde gerne auf eval() verzichten

      Ist eval() nicht für genau solche Fälle gedacht!?

      Einerseits wohl schon, andererseits wurd's zum Parsen von JSON missbraucht (bevor es JSON.parse() gab). Wie gesagt im strict mode ist es ganz verboten.

      Mit dem Objekt kann ich jetzt auch die Variablen a und b unterschiedlich anlegen.

      Bis demnächst
      Matthias

      Herzliche Grüße

      Matthias Scharwies

      --
      Es gibt viel zu tun: ToDo-Liste
      1. problematische Seite

        Hallo Matthias,

        Ich würde gerne auf eval() verzichten

        Ist eval() nicht für genau solche Fälle gedacht!?

        Einerseits wohl schon, andererseits wurd's zum Parsen von JSON missbraucht (bevor es JSON.parse() gab). Wie gesagt im strict mode ist es ganz verboten.

        es gibt immer noch die „Nobelversion“ von eval: Function. Die verwende ich im Funktionsplotter

        Gruß
        Jürgen

      2. problematische Seite

        Wenn du es so schreibst, ist ergebnis eine globale Variable.

        Wär' ja auch kein Problem, ich hatte eigentlich ziemlich viel globale Variablen am Anfang, die jetzt zum überwiegenden Teil in die task()-Funktion gewandert sind.

        Matthias (A.) hat sich nicht den kompletten Source angeschaut. ergebnis ist eine lokale Variable des DOMContentLoaded Handlers und verpestet damit nicht den globalen Namespace.

        Insofern: Eine Form des Module Pattern. Überhaupt kein Problem.

        Rolf

  5. problematische Seite

    Hello Matthias,

    könntest Du die Aufgabenstellung, bzw. den Ablauf der Aufgabenbearbeitung nochmal beschreiben?
    Ich habe das Gefühl, dass Du dich hier verzettelt hast.

    In welcher Reihenfolge finden die unterschiedlichen Bildschirmanuzeigen, die Auswahl durch den "Spieler" und das Auswürfeln der Zahlen statt? Ich schlage mal vor:

    • Der Spieler wählt eine Rechenart aus
    • die Rechenart wird ermittelt und angezeigt
    • die Zahlen dazu werden ausgewürfelt
    • das Ergebnis muss eingegeben werden
    • Die Lösung wird ermittelt und die Punkte (pro Rechenart) gezählt.

    Wenn Du dich an diese Reihenfolge halten würdest, bräuchtest Du bei einfachen Aufgbane mit zwei Operanden und einem Operator

    • kein eval()
    • könnest die Zahlen rückwärts ermitteln (so meinte das RR vermutlich)
    • dir keine weiteren Gedanken mehr machen, wie Du nichtganzzahlige oder negative Ergebnisse vermeidest

    Liebe Grüße
    Tom S.

    --
    Es gibt nichts Gutes, außer man tut es
    Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
    1. problematische Seite

      Servus!

      Vielen Dank für die vielen Anregungen! Ich mach das Spiel am Wochenende weiter - wollte Euch aber noch einen Zwischenstand feedbacken:

      könntest Du die Aufgabenstellung, bzw. den Ablauf der Aufgabenbearbeitung nochmal beschreiben?
      Ich habe das Gefühl, dass Du dich hier verzettelt hast.

      Das kann gut sein. Einerseits habe ich eine grobe Vorstellung, was das komplette Spiel soll: Grundrechenarten mit ganzen Zahlen für 1.-8.Klässler, (also keine gemischten Zahlen, Brüche usw -> wär aber auch mal interessant.)

      Wie hier gesagt, bei Divisionen und Subtraktionen sollten positive Ganzzahlen rauskommen, das muss ich noch ändern.

      In welcher Reihenfolge finden die unterschiedlichen Bildschirmanuzeigen, die Auswahl durch den "Spieler" und das Auswürfeln der Zahlen statt? Ich schlage mal vor:

      • Der Spieler wählt eine Rechenart aus
      • die Rechenart wird ermittelt und angezeigt
      • die Zahlen dazu werden ausgewürfelt
      • das Ergebnis muss eingegeben werden
      • Die Lösung wird ermittelt und die Punkte (pro Rechenart) gezählt.

      Wenn Du dich an diese Reihenfolge halten würdest, bräuchtest Du bei einfachen Aufgbane mit zwei Operanden und einem Operator

      Ja, mich hat einfach irritiert, dass der Operator ein string und kein Operator war; auf so was wie PLs

      if(operator == 'plus'){ x = a + b }

      bin ich eben grade nicht gekommen, bzw. hätte es als mehrfach verschachteltes Monster für alle Fälle angelegt. Ich hatte vor Jahren schonmal eine Variante mit select-Menü, onclick-Buttons und je einer Funktion pro Operator programmiert / aus dem Netz kopiert / angepasst.

      Wenn das Spiel dann mal läuft, denke ich über zwei verschiedene Modi nach:

      • a + b = ?

      • a + ? = b

      Dafür müsste die Position des input-elements mit dem span-Element vertauscht werden, das würde ich evtl. mit dem template-Element erldigen wollen.

      @JürgenB input type="number" hab ich auch schon überlegt, wegen der Scrollbalken rechts wieder verworfen -> wäre aber grade mit step="1" für ganze Zahlen nützlich.

      @Rolf b Ja, der Ergebnisvergleich muss in eine eigene Funktion, mach ich Freitag.

      @Gunnar Bittersmann Gute Idee mit den Sonderzeichen - ist schon umgesetzt!

      So jetzt muss ich essen kochen - Familie kommt gleich heim!

      Liebe Grüße
      Tom S.

      Herzliche Grüße

      Matthias Scharwies

      --
      Es gibt viel zu tun: ToDo-Liste
      1. problematische Seite

        Hallo Matthias Scharwies,

        Grundrechenarten mit ganzen Zahlen für 1.-8.Klässler, (also keine gemischten Zahlen, Brüche usw)

        Dann wohl eher 1. bis 4. Klasse 😂, Bruchrechnung beginnt spätestens in 5. Ganze Zahlen können auch negativ sein. 😉 Rationale Zahlen stehen spätestens in 7 auf dem Lehrplan. 😂

        Bis demnächst
        Matthias

        --
        Rosen sind rot.
        1. problematische Seite

          Tach!

          Grundrechenarten mit ganzen Zahlen für 1.-8.Klässler, (also keine gemischten Zahlen, Brüche usw)

          Dann wohl eher 1. bis 4. Klasse 😂, Bruchrechnung beginnt spätestens in 5. Ganze Zahlen können auch negativ sein. 😉 Rationale Zahlen stehen spätestens in 7 auf dem Lehrplan. 😂

          Er ist Lehrer in Bayern, da ist das alles etwas anders. *duckundwech*

          dedlfix.

          1. problematische Seite

            Hallo dedlfix,

            Er ist Lehrer in Bayern, da ist das alles etwas anders. *duckundwech*

            Das stimmt. In dem Fall aber eher in die andere Richtung. 😉

            Bis demnächst
            Matthias

            --
            Rosen sind rot.
          2. problematische Seite

            Servus!

            Grundrechenarten mit ganzen Zahlen für 1.-8.Klässler,

            Dann wohl eher 1. bis 4. Klasse 😂, Bruchrechnung beginnt spätestens in 5. Ganze Zahlen können auch negativ sein. 😉 Rationale Zahlen stehen spätestens in 7 auf dem Lehrplan. 😂

            Das soll ja eher eine spielerische Wiederholung als eine Arbeit an Neuem sein.

            Er ist Lehrer in Bayern, da ist das alles etwas anders. *duckundwech*

            Ich habe jetzt grad 'ne 10. im mathematisch-naturwissenschaftlichen Zweig durchgebracht und war immer schockiert, wenn ich reinkam und den Tafelanschrieb in Mathe sah - alles vergessen in den letzten 30Jahren.

            In Englisch waren in der Abschlussprüfung aber nicht die schwierigen Sachen entscheidend - die Schüler lassen die Punkte eher mit den einfachen Sachen wie he,she,it -s und word order liegen - leider!

            Da müsste man sie mit spielerischen Mitteln zum Üben „locken“.

            Herzliche Grüße

            Matthias Scharwies

            --
            Es gibt viel zu tun: ToDo-Liste
      2. problematische Seite

        Servus! Vielen Dank für die vielen Anregungen! Jetzt läuft's!

        [...] auf so was wie PLs if(operator == 'plus'){ x = a + b } bin ich eben grade nicht gekommen

        lol - die alte Version mit dem select-Menü hatte so was drin:

               if (rechenArt=="2")
                  {
                  operator = "-";
                  zahl2=rand(1,oberzahl*oberzahl);
                  zahl1=rand(zahl2,oberzahl*oberzahl);
                  loesung = zahl1 - zahl2;
               }
        

        Das habe ich leider nicht angeguckt. Jetzt ist es aber drin.

        @JürgenB input type="number" hab ich auch schon überlegt, wegen der Scrollbalken rechts wieder verworfen -> wäre aber grade mit step="1" für ganze Zahlen nützlich.

        Habe ich implementiert!

        Ergebnisstatistik und mehrere Modi mach ich am Wochenende weiter.

        Herzliche Grüße

        Matthias Scharwies

        Herzliche Grüße

        Matthias Scharwies

        --
        Es gibt viel zu tun: ToDo-Liste
        1. problematische Seite

          Hello,

          Screenshot Mathe-Quiz

          Schade, das sieht bei mir jetzt so aus!

          Liebe Grüße
          Tom S.

          --
          Es gibt nichts Gutes, außer man tut es
          Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
          1. problematische Seite

            @@TS

            Screenshot Mathe-Quiz

            Schade, das sieht bei mir jetzt so aus!

            Hast du deinem Windows nur den Look von Windows 95/98 verpasst oder läuft bei dir tatsächlich noch Windows 95/98? Wenn dein System keine Schriftart mit Glyphen für bestimmte Zeichen zur Verfügung stellt, kannst du halt nicht erwarten, die Zeichen angezeigt zu bekommen.

            Was auch bei mir falsch ist, ist der rechte Button. Da wird einem ein X für ein Mal vorgemacht und anstatt Minuszeichen ist Fliegendreck auf dem Bildschirm. Die Ausrichtung der Zeichen stimmt auch nicht.

            LLAP 🖖

            --
            “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
            1. problematische Seite

              Hallo,

              Fliegendreck auf dem Bildschirm.

              Bei mir hilft dieses hier

              Gruß
              Kalk

              1. problematische Seite

                Hallo

                Fliegendreck auf dem Bildschirm.

                Bei mir hilft dieses hier

                auch bei der hier?

                Laufende Fliege

                Gruß
                Jürgen

                PS Ich würde das Bild gerne mit eine Quellenangabe versehen, aber ich habe mir leider nicht gemerkt, wo ich es gefunden habe.

                1. problematische Seite

                  @@JürgenB

                  PS Ich würde das Bild gerne mit eine Quellenangabe versehen, aber ich habe mir leider nicht gemerkt, wo ich es gefunden habe.

                  Quelle: Internet

                  Machen doch alle™ so.

                  LLAP 🖖

                  --
                  “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
                2. problematische Seite

                  Hello,

                  auch bei der hier?

                  Laufende Fliege

                  PS Ich würde das Bild gerne mit eine Quellenangabe versehen, aber ich habe mir leider nicht gemerkt, wo ich es gefunden habe.

                  Ich habe das auch mal bekommen als Desktop-Background. Da ist es wirklich irritierend.

                  Liebe Grüße
                  Tom S.

                  --
                  Es gibt nichts Gutes, außer man tut es
                  Andersdenkende waren noch nie beliebt, aber meistens diejenigen, die die Freiheit vorangebracht haben.
        2. problematische Seite

          Hallo,

          Jetzt läuft's!

          Hm, dann sollte ich wohl die Grundschule wiederholen, ich hab bisher nur "Leider falsch" als Antwort bekommen...

          Gruß
          Kalk