Mostra le tracce del puntatore del mouse ... del futuro!


24

Ispirato da questo esempio di utilizzo di d3js , ti sfido a creare un'area di disegno (o l'equivalente della lingua scelta) in cui verranno visualizzati i percorsi del puntatore del mouse , con la seguente svolta:

The Twist

Si consiglia di non visualizzare i sentieri del luogo in cui il puntatore del mouse è stato , ma il "sentieri" di cui sarà (potrebbe) essere in futuro.

Puoi farlo usando:

  1. Una macchina del tempo, o

  2. Stime probabilistiche basate su precedenti movimenti del mouse

ipotesi

Nel caso in cui non sia stata scelta l'implementazione della macchina del tempo, quando il mouse non si sposta per più di una soglia di millisecondi, non è possibile visualizzare nessuno dei percorsi. (Il valore di soglia spetta a te scegliere).

L'immagine del cursore dipende da te e non deve essere la stessa del cursore del sistema operativo (puoi anche disegnare piccoli cerchi o punti).

Nessun input malvagio verrà testato: puoi presumere che i movimenti siano fluidi. La definizione 'liscia' per questo caso è: se i movimenti del mouse fossero una funzione sull'asse xey della tela, sarebbe una funzione continua.

vincente

La risposta valida con il minor numero di caratteri nel codice vincerà. In caso di pareggio, vincerà quello che è stato pubblicato per primo.

EDIT: vincerà la risposta valida con il maggior numero di voti . In caso di pareggio, vincerà quello che è stato pubblicato per primo. Puoi essere creativo sull'implementazione o essere preciso con la previsione. Non sono più il giudice, lo siamo tutti :)

  • Una risposta valida deve includere un modo con cui giocare (test! Intendo test), su uno strumento online o su un compilatore / interprete / runtime / ecc. Liberamente scaricabile.

2
Penso che questa domanda potrebbe essere più adatta a una gara di popolarità che a un code-golf, perché è abbastanza soggettiva su ciò che si qualifica come una previsione abbastanza buona. Consiglierei di chiarirlo o di cambiare il tag. Tuttavia, sembra divertente.
isaacg,

2
Hai ragione. Ho modificato la domanda e modificato il tag.
Jacob,

Tempo per qualcuno di implementare algoritmi di apprendimento automatico!
Ingo Bürk,

6
A scopo di test, a quali modelli di macchina del tempo hai accesso? E possiamo usare le librerie standard per interfacciarci con loro?
Peter Taylor,

1
Solo un matematico piagnucolare qui: liscio! = Continuo. In effetti il ​​movimento selvaggio e spikey sarà ancora continuo.
CompuChip,

Risposte:


33

Javascript

Il mio programma prevede la direzione del puntatore usando la media del cambiamento angolare nella direzione degli ultimi 20 movimenti del mouse. Utilizza anche la varianza del cambiamento angolare per creare una "nuvola" di possibili posizioni e direzioni del puntatore. Il colore di ciascun puntatore nella "nuvola" dovrebbe rappresentare la probabilità che sia la nuova posizione del puntatore del mouse, dove i colori più scuri rappresentano una maggiore probabilità. La distanza della nuvola del puntatore davanti al mouse viene calcolata usando la velocità del movimento del mouse. Non fa le migliori previsioni ma sembra pulito.

Ecco un violino: http://jsfiddle.net/5hs64t7w/4/

È interessante vedere aumentare le dimensioni della nuvola di puntatori. Può essere impostato cambiando la cloudSizevariabile sulla prima riga del programma. Ecco un violino con una dimensione di nuvola di 10: http://jsfiddle.net/5hs64t7w/5/

Ho usato queste fonti per ottenere formule per media circolare e varianza:
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

Ecco il codice se qualcuno è interessato:

    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;
    };

2
È possibile visualizzare una sequenza di puntatore del mouse (con orientamento fisso) anziché un puntatore che punta verso la direzione variabile? Mi aspettavo di vedere "tracce del topo" ma non ne vedo nessuna, ahah
solo il

Molto bello, ma non è più plausibile che il puntatore si alzi in futuro quando attualmente scende? Il programma dovrebbe fare esattamente il contrario, quindi prevede che il puntatore rimanga sullo schermo.
Madmenyo,

@MennoGouw non è perfetto ma è dannatamente buono
NimChimpsky

@nimchimpsky Solo dicendo che la probabilità che il mouse salga è più alta se il mouse attualmente scende. Il programma in sé è eccezionale.
Madmenyo,

Pensi che sia anche possibile usare il solito comportamento umano per la gestione del mouse? Come cerchi, linee rette ... Questi potrebbero essere previsti ancora di più in futuro (calcolando il raggio del cerchio dopo un paio di misurazioni e finendo il cerchio anche prima che tu l'abbia disegnato)
Zafferano,

14

Giava

Ho deciso di adottare l'approccio della macchina del tempo. Si scopre che l'ingrediente chiave di una macchina del tempo è java.awt.Robot. Il mio programma ti consente di spostare il mouse per 10 secondi. Dopo i 10 secondi torna indietro nel tempo e ricrea il movimento del mouse, prevedendolo perfettamente.

inserisci qui la descrizione dell'immagine

Ecco il codice:

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);
    }

}

Codice leggermente ottimizzato da Netbeans (eliminato gli avvisi): pastebin.com/E57LZ4zY
Kaz Wolfe

10

Vanilla Javascript

Giusto per iniziare, ecco una semplice previsione basata su due valori. Le ultime posizioni del nmouse vengono memorizzate e mantenute in una coda, la previsione è una semplice estrapolazione lineare del primo e dell'ultimo elemento nella coda.

Questo è solo il codice di previsione, il codice completo inclusa la demo può essere visto 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;
}

La demo contiene un commento nella previsione che consente invece di utilizzare gli ultimi due elementi nella coda per la previsione. Rende il risultato più "in tempo reale", ma anche meno "liscio".

Se qualcuno vuole utilizzare il boilerplate workper implementare un diverso algoritmo di predizione, sentiti libero. Non è molto lavoro comunque.


Puoi visualizzare un puntatore del mouse anziché una linea? Mi aspettavo di vedere "tracce del topo" ma non ne vedo nessuna, ahah
solo il

La domanda dice che non deve essere un cursore;)
Ingo Bürk,

4

Javascript

Il passato è la migliore previsione per il futuro - io e probabilmente anche qualcun altro

La mia soluzione è molto semplice Innanzitutto, ecco il >>> Fiddle! <<<

Tutto ciò che fa è spostare la traccia passata, quindi sembra la traccia futura. Fondamentalmente non è coinvolta la matematica (lo so, piuttosto noiosa). Puoi facilmente vedere gli errori, specialmente quando sposti il ​​cursore in cerchio. Ecco perché ho reso il percorso così breve;)

Il codice:

<!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>

ahah ho appena dato un'occhiata alla data. Qualunque cosa, mi piace
Felk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.