Zeigen Sie die Spuren des Mauszeigers an… der Zukunft!

24

Inspiriert von diesem Beispiel für die Verwendung von d3js fordere ich Sie auf, eine Zeichenfläche (oder eine Sprache Ihrer Wahl) zu erstellen, in der die Spuren des Mauszeigers mit der folgenden Drehung angezeigt werden:

Der Twist

Sie sollten nicht die Spuren anzeigen, auf denen sich der Mauszeiger befand , sondern die "Spuren", auf denen er sich (möglicherweise) in Zukunft befinden wird.

Sie können es tun, indem Sie entweder:

  1. Eine Zeitmaschine oder

  2. Wahrscheinlichkeitsschätzungen basierend auf vorherigen Mausbewegungen

Annahmen

Im Fall haben Sie die Zeitmaschine Implementierung nicht wählen, wenn die Maus nicht mehr als bewegen Schwelle , Millisekunden Sie keine der Routen anzeigen können. (Der Schwellenwert liegt bei Ihnen).

Das Cursorbild liegt bei Ihnen und muss nicht mit dem Cursor des Betriebssystems identisch sein (Sie können sogar einfache kleine Kreise oder Punkte zeichnen).

Es wird keine böse Eingabe getestet: Sie können davon ausgehen, dass die Bewegungen reibungslos sind. Die Definition für "reibungslos" in diesem Fall lautet: Wenn die Mausbewegungen eine Funktion über die x- und y-Achse der Zeichenfläche wären, wäre dies eine kontinuierliche Funktion.

Gewinnen

Die gültige Antwort mit den wenigsten Zeichen im Code gewinnt. Bei einem Gleichstand gewinnt derjenige, der zuerst gebucht wurde.

EDIT: Die gültige Antwort mit den meisten Upvotes gewinnt. Bei einem Gleichstand gewinnt derjenige, der zuerst gebucht wurde. Sie können kreativ bei der Implementierung sein oder präzise bei der Vorhersage. Ich bin nicht mehr der Richter, wir alle sind :)

  • Eine gültige Antwort muss eine Möglichkeit enthalten, mit der ich spielen kann (Test! Ich meinte Test), entweder auf einem Online-Tool oder auf einem frei herunterladbaren Compiler / Interpreter / Runtime / etc.
Jacob
quelle
2
Ich denke, diese Frage eignet sich besser für einen Beliebtheitswettbewerb als für ein Code-Golfspiel, da es ziemlich subjektiv ist, was als ausreichend gute Vorhersage zu qualifizieren ist. Ich würde empfehlen, dies zu klären oder das Tag zu ändern. Sieht trotzdem lustig aus.
Isaacg
2
Du hast recht. Ich habe die Frage bearbeitet und das Tag geändert.
Jacob
Zeit für jemanden, Algorithmen für maschinelles Lernen zu implementieren!
Ingo Bürk
6
Auf welche Modelle von Zeitmaschinen haben Sie zu Testzwecken Zugriff? Und dürfen wir Standardbibliotheken verwenden, um mit ihnen zu kommunizieren?
Peter Taylor
1
Nur ein Mathematiker jammert hier: glatt! = Stetig. Tatsächlich wird die wilde Stachelbewegung immer noch andauernd sein.
CompuChip

Antworten:

33

Javascript

Mein Programm sagt die Richtung des Zeigers voraus, indem es den Durchschnitt der Winkeländerung in Richtung der letzten 20 Mausbewegungen verwendet. Sie verwendet auch die Varianz der Winkeländerung, um eine "Wolke" möglicher Positionen und Richtungen des Zeigers zu erzeugen. Die Farbe jedes Zeigers in der "Wolke" soll die Wahrscheinlichkeit darstellen, dass es sich um die neue Position des Mauszeigers handelt, wobei dunklere Farben eine größere Wahrscheinlichkeit darstellen. Die Entfernung der Zeigerwolke vor der Maus wird anhand der Geschwindigkeit der Mausbewegung berechnet. Es macht nicht die besten Vorhersagen, aber es sieht ordentlich aus.

Hier ist eine Geige: http://jsfiddle.net/5hs64t7w/4/

Es ist interessant, die Zeigerwolke zu vergrößern. Dies kann durch Ändern der cloudSizeVariablen in der ersten Zeile des Programms eingestellt werden. Hier ist eine Geige mit einer Wolkengröße von 10: http://jsfiddle.net/5hs64t7w/5/

Ich habe diese Quellen verwendet, um Formeln für den Mittelwert und die Varianz zu erhalten:
Circular Mean: http://en.wikipedia.org/wiki/Circular_mean
Circular Variance: http://www.ebi.ac.uk/thornton-srv/software/ PROCHECK / nmr_manual / man_cv.html

Hier ist der Code, wenn jemand interessiert ist:

    var cloudSize = 3;

    var canvas = document.getElementById('canvas_element');
    var c = canvas.getContext('2d');
    var prevX = -1;
    var prevY = -1;
    var curX = -1;
    var curY = -1;
    var distance = 0;
    var direction = 0;

    function drawMouse(x, y, angle, gray){
        var grayVal = Math.round(gray*255);
        var grayString = "rgb(" + grayVal + "," + grayVal +"," + grayVal + ")";
        c.fillStyle = grayString;
        c.strokeStyle = grayString;
        c.lineWidth = 1;
        c.beginPath();
        c.moveTo(x, y);
        c.lineTo(x + 16*Math.cos(angle + Math.PI/2.0 + Math.PI/8.0), y + 16*Math.sin(angle + Math.PI/2.0 + Math.PI/8.0));
        c.moveTo(x, y);
        c.lineTo(x + 16*Math.cos(angle + Math.PI/2.0 - Math.PI/8.0), y + 16*Math.sin(angle + Math.PI/2.0 - Math.PI/8.0));
        c.lineTo(x + 16*Math.cos(angle + Math.PI/2.0 + Math.PI/8.0), y + 16*Math.sin(angle + Math.PI/2.0 + Math.PI/8.0));
        c.stroke();
        c.fill();
        c.beginPath();
        c.moveTo(x, y);
        c.lineTo(x + 24*Math.cos(angle + Math.PI/2), y + 24*Math.sin(angle + Math.PI/2));
        c.stroke();
    }

    function sum(array){
        var s = 0.0;
        for(var i=0; i<array.length; i++){
            s += array[i];
        }
        return s;
    }

    var sins = [];
    var coss = [];
    var lengths = [];
    var times = [];
    var index = 0;
    var limit = 20;
    var variance = 0;
    var prevTime = new Date().getTime();
    function updateDistanceAndDirection(x, y){
        var angle = Math.atan2(prevY - curY, prevX - curX);
        sins[index] = Math.sin(angle);
        coss[index] = Math.cos(angle);
        lengths[index] = Math.sqrt((curX-prevX)*(curX-prevX) + (curY-prevY)*(curY-prevY));
        var time = new Date().getTime();
        times[index] = time - prevTime;

        variance = 1.0 - Math.sqrt(sum(coss)*sum(coss)+sum(sins)*sum(sins))/sins.length;

        direction = Math.atan2(1/sins.length*sum(sins),1/coss.length*sum(coss));
        var speed = sum(lengths)/(sum(times)/200);
        distance = Math.min(Math.max(40, speed), 100);
        prevTime = time;
        index = (index+1)%limit;
    }

    function drawMice(count){
        c.clearRect(0, 0, canvas.width, canvas.height);

        for(var i=count; i>=0; i--){
            var dir = direction + i*variance;
            drawMouse(curX - distance*Math.cos(dir), curY - distance*Math.sin(dir), dir - Math.PI/2, i/count);
            dir = direction - i*variance;
            drawMouse(curX - distance*Math.cos(dir), curY - distance*Math.sin(dir), dir - Math.PI/2, i/count);
        }
    }

    canvas.onmousemove = function (event) {
        curX = event.clientX;
        curY = event.clientY;

        updateDistanceAndDirection(curX, curY);

        drawMice(cloudSize);

        prevX = curX;
        prevY = curY;
    };
Rhabarber-Vanillesoße
quelle
2
Können Sie eine Sequenz von Mauszeigern (mit fester Ausrichtung) anstelle eines Zeigers anzeigen, der in eine variable Richtung zeigt? Ich hatte erwartet, "
Mausspuren
Sehr schön, aber ist es nicht plausibler, dass der Zeiger in Zukunft nach oben geht, wenn er gerade nach unten geht? Imho, das Programm sollte genau das Gegenteil tun, so dass es vorhersagt, dass der Zeiger auf dem Bildschirm bleibt.
Madmenyo
@ MennoGouw es ist nicht perfekt, aber es ist verdammt gut
NimChimpsky
@nimchimpsky Nur zu sagen, dass die Wahrscheinlichkeit, dass die Maus nach oben geht, höher ist, wenn die Maus gerade nach unten geht. Das Programm selbst ist großartig.
Madmenyo
Denken Sie, dass es auch möglich ist, das übliche menschliche Verhalten für den Umgang mit Mäusen zu verwenden? Wie Kreise, gerade Linien ... Diese könnten in Zukunft noch weiter vorhergesagt werden (Berechnen des Radius des Kreises nach ein paar Messungen und Beenden des Kreises, noch bevor Sie ihn entworfen haben)
Safran
14

Java

Ich entschied mich für den Zeitmaschinenansatz. Es stellt sich heraus, dass der Schlüsselbestandteil einer Zeitmaschine java.awt.Robot ist. Mit meinem Programm können Sie Ihre Maus 10 Sekunden lang bewegen. Nach den 10 Sekunden geht es in die Vergangenheit zurück und erstellt Ihre Mausbewegung neu, während Sie diese perfekt vorhersagen.

Bildbeschreibung hier eingeben

Hier ist der Code:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;


public class TimeMachine extends JPanel implements MouseMotionListener {

    Timer timer;
    int time = 10;
    java.util.Timer taskTimer;
    ArrayList<Point> mousePoints;
    ArrayList<Long> times;
    Robot robot;
    int width, height;
    ArrayList<Point> drawMousePoints;

    public TimeMachine(){
        width = 500;
        height = 500;
        drawMousePoints = new ArrayList<Point>();

        robot = null;
        try{
            robot = new Robot();
        }
        catch(Exception e){
            System.out.println("The time machine malfunctioned... Reverting to 512 BC");
        }
        mousePoints = new ArrayList<Point>();
        times = new ArrayList<Long>();

        taskTimer = new java.util.Timer();

        ActionListener al = new ActionListener(){
            public void actionPerformed(ActionEvent e){
                time--;
                if(time == 0)
                    rewind();
                repaint();
            }
        };
        timer = new Timer(1000, al);
        start();
    }

    public void paint(Graphics g){
        g.clearRect(0, 0, width, height);
        g.drawString("Time Machine activiates in: " + time, 15, 50);
        for(int i=0; i<drawMousePoints.size(); i++){
            Point drawMousePoint = drawMousePoints.get(i);
            drawMouse(drawMousePoint.x-getLocationOnScreen().x, drawMousePoint.y-getLocationOnScreen().y, g, Color.BLACK, Color.LIGHT_GRAY, (double)i/drawMousePoints.size());
        }
    }

    public void drawMouse(int x, int y, Graphics g, Color line, Color fill, double alpha){
        Graphics2D g2d = (Graphics2D)g;
        g2d.setColor(new Color(fill.getRed(), fill.getGreen(), fill.getBlue(), (int)Math.max(Math.min(alpha*255, 255), 0)));
        g2d.fillPolygon(new int[]{x, x, x+4, x+8, x+10, x+7, x+12}, new int[]{y, y+16, y+13, y+20, y+19, y+12, y+12}, 7);

        g2d.setColor(new Color(line.getRed(), line.getGreen(), line.getBlue(), (int)Math.max(Math.min(alpha*255, 255), 0)));
        g2d.drawLine(x, y, x, y + 16);
        g2d.drawLine(x, y+16, x+4, y+13);
        g2d.drawLine(x+4, y+13, x+8, y+20);
        g2d.drawLine(x+8, y+20, x+10, y+19);
        g2d.drawLine(x+10, y+19, x+7, y+12);
        g2d.drawLine(x+7, y+12, x+12, y+12);
        g2d.drawLine(x+12, y+12, x, y);
    }

    public void start(){
        timer.start();
        prevTime = System.currentTimeMillis();
        mousePoints.clear();
    }

    public void rewind(){
        timer.stop();
        long timeSum = 0;
        for(int i=0; i<times.size(); i++){
            timeSum += times.get(0);
            final boolean done = i == times.size()-1;
            taskTimer.schedule(new TimerTask(){
                public void run(){
                    Point point = mousePoints.remove(0);
                    drawMousePoints.clear();
                    drawMousePoints.addAll(mousePoints.subList(0, Math.min(mousePoints.size(), 30)));
                    robot.mouseMove(point.x, point.y);
                    repaint();
                    if(done)
                        System.exit(0);
                }
            }, timeSum);
        }
    }

    long prevTime = 0;
    public void record(MouseEvent m){
        if(timer.isRunning()){
            long time = System.currentTimeMillis();
            mousePoints.add(new Point(m.getXOnScreen(), m.getYOnScreen()));
            times.add((time-prevTime)/10);
            prevTime = time;
        }
    }

    public static void main(String[] args){

        TimeMachine timeMachine = new TimeMachine();

        JFrame frame = new JFrame("Time Machine");
        frame.setSize(timeMachine.width, timeMachine.height);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.addMouseMotionListener(timeMachine);

        frame.add(timeMachine);
    }

    public void mouseDragged(MouseEvent m) {
        record(m);
    }

    public void mouseMoved(MouseEvent m) {
        record(m);
    }

}
Rhabarber-Vanillesoße
quelle
Von Netbeans leicht optimierter Code (die Warnungen wurden entfernt): pastebin.com/E57LZ4zY
Kaz Wolfe
10

Vanille Javascript

Um den Anfang zu machen, folgt hier eine einfache Vorhersage, die auf zwei Werten basiert. Die letzten nMauspositionen werden gespeichert und in einer Warteschlange gespeichert. Die Vorhersage ist eine einfache lineare Extrapolation des ersten und letzten Elements in der Warteschlange.

Dies ist nur der Vorhersagecode. Den vollständigen Code einschließlich der Demo finden Sie in this fiddle:

function predict(trail) {
    var b = trail.pop(),
        a = trail[0],
        d = {
            x: b.x - a.x,
            y: b.y - a.y
        },
        m = Math.sqrt( d.x * d.x + d.y * d.y );

    d.x = 5 * d.x / m;
    d.y = 5 * d.y / m;

    var predictions = [];
    for(var i = 1; i <= 10; i++) {
        predictions.push({
            x: b.x + i * d.x,
            y: b.y + i * d.y
        });
    }

    return predictions;
}

Die Demo enthält einen Kommentar in der Vorhersage, mit dem Sie stattdessen die letzten beiden Elemente in der Warteschlange für die Vorhersage verwenden können. Macht das Ergebnis "Echtzeit", aber auch weniger "glatt".

Wenn jemand boilerplate workeinen anderen Vorhersagealgorithmus implementieren möchte , zögern Sie nicht. Es ist sowieso nicht viel Arbeit.

Ingo Bürk
quelle
Können Sie einen Mauszeiger anstelle einer Linie anzeigen? Ich hatte erwartet, "
Mausspuren
Die Frage besagt, dass es kein Cursor sein muss;)
Ingo Bürk
4

Javascript

Die Vergangenheit ist die beste Vorhersage für die Zukunft - ich und wahrscheinlich auch jemand anderes

Meine Lösung ist sehr einfach. Hier ist zuerst die >>> Geige! <<<

Alles, was es tut, ist die Vergangenheit zu verschieben, so dass es aussieht wie die Zukunftsspur. Grundsätzlich ist keine Mathematik beteiligt (ich weiß, ziemlich langweilig). Sie können die Fehler leicht erkennen, insbesondere wenn Sie den Cursor in Kreisen bewegen. Deshalb habe ich den Weg so kurz gemacht;)

Der Code:

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
            .cursor {
                width: 12px;
                height: 19px;
                position: absolute;
                background-image: url(https://i.imgur.com/h8imKBP.png);
            }
        </style>
        <script type="text/javascript">

            var x, y;
            window.onmousemove = function(e) {x=e.clientX; y=e.clientY;}

            var p = [0,0,0,0,0,0,0,0,0,0];
            window.setInterval(function() {
                p.shift();
                p.push([x, y]);
                var diff = [x-p[0][0], y-p[0][1]];
                for (var i = 0; i < 10; i++) {
                    var e = document.getElementById(i);
                    e.style.left = (p[9-i][0]+diff[0])+"px";
                    e.style.top = (p[9-i][1]+diff[1])+"px";
                }
            }, 10);

        </script>
    </head>
    <body>
    <div id="0" class="cursor"></div>
    <div id="1" class="cursor"></div>
    <div id="2" class="cursor"></div>
    <div id="3" class="cursor"></div>
    <div id="4" class="cursor"></div>
    <div id="5" class="cursor"></div>
    <div id="6" class="cursor"></div>
    <div id="7" class="cursor"></div>
    <div id="8" class="cursor"></div>
    <div id="9" class="cursor"></div>
    </body>
</html>
Felk
quelle
haha ich habe mir gerade das datum angeschaut. Wie auch immer, ich mag es
Felk