Tampilkan jejak penunjuk tetikus ... di masa depan!

24

Terinspirasi oleh contoh ini menggunakan d3js , saya menantang Anda untuk membuat kanvas (atau bahasa pilihan Anda) di mana jejak penunjuk mouse akan ditampilkan, dengan twist berikut:

Twist

Anda tidak boleh menampilkan jejak di mana penunjuk tetikus itu berada , tetapi "jejak" di mana ia akan (mungkin) berada di masa depan.

Anda dapat melakukannya dengan menggunakan:

  1. Mesin waktu, atau

  2. Estimasi probabilitas berdasarkan pergerakan mouse sebelumnya

Asumsi

Jika Anda tidak memilih penerapan mesin waktu, saat mouse tidak bergerak lebih dari ambang milidetik, Anda tidak dapat menampilkan jejak apa pun. (Nilai ambang terserah Anda untuk memilih).

Gambar kursor terserah Anda dan tidak harus sama dengan kursor OS (Anda bahkan dapat menggambar lingkaran atau titik kecil sederhana).

Tidak ada input jahat yang akan diuji: Anda dapat menganggap gerakannya lancar. Definisi 'halus' untuk kasus ini adalah: jika gerakan mouse adalah fungsi di atas sumbu x dan y kanvas - itu akan menjadi fungsi kontinu.

Kemenangan

Jawaban yang valid dengan karakter paling sedikit dalam kode akan menang. Seandainya seri - yang dipasang pertama kali akan menang.

EDIT: Jawaban yang valid dengan sebagian besar upvotes akan menang. Seandainya seri - yang dipasang pertama kali akan menang. Anda bisa kreatif pada implementasi, atau tepat dengan prediksi. Saya bukan hakim lagi, kita semua :)

  • Sebuah jawaban yang valid harus menyertakan cara bagi saya untuk bermain (test! Maksud saya test), baik pada alat online atau pada kompiler / interpreter / runtime / etc yang dapat didownload secara bebas.
Yakub
sumber
2
Saya pikir pertanyaan ini mungkin lebih cocok untuk kontes popularitas daripada golf kode, karena cukup subyektif untuk apa yang memenuhi syarat sebagai prediksi yang cukup baik. Saya akan merekomendasikan klarifikasi itu atau mengubah tag. Meski begitu, terlihat menyenangkan.
isaacg
2
Kamu benar. Saya mengedit pertanyaan dan mengubah tag.
Yakub
Saatnya seseorang menerapkan algoritma pembelajaran mesin!
Ingo Bürk
6
Untuk tujuan pengujian, model mesin waktu mana yang Anda punya akses? Dan bisakah kita menggunakan perpustakaan standar untuk berinteraksi dengan mereka?
Peter Taylor
1
Hanya seorang matematikawan yang merengek di sini: halus! = Terus menerus. Bahkan pergerakan spikey liar masih akan terus menerus.
CompuChip

Jawaban:

33

Javascript

Program saya memprediksi arah pointer dengan menggunakan rata-rata perubahan sudut dalam arah 20 gerakan mouse terakhir. Ini juga menggunakan varians dari perubahan sudut untuk membuat "cloud" dari kemungkinan lokasi dan arah penunjuk. Warna setiap pointer di "cloud" seharusnya mewakili kemungkinan itu menjadi posisi baru dari pointer mouse, di mana warna yang lebih gelap mewakili kemungkinan yang lebih besar. Jarak awan penunjuk di depan mouse dihitung menggunakan kecepatan gerakan mouse. Itu tidak membuat prediksi terbaik tetapi terlihat rapi.

Ini biola: http://jsfiddle.net/5hs64t7w/4/

Meningkatkan ukuran cloud penunjuk ini menarik untuk dilihat. Itu dapat diatur dengan mengubah cloudSizevariabel pada baris pertama program. Berikut adalah biola dengan ukuran awan 10: http://jsfiddle.net/5hs64t7w/5/

Saya menggunakan sumber-sumber ini untuk mendapatkan rumus untuk mean melingkar dan varians:
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

Ini kode jika ada yang tertarik:

    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;
    };
Rhubarb Custard
sumber
2
Bisakah Anda menampilkan urutan pointer mouse (dengan orientasi tetap) alih-alih pointer yang menunjuk ke arah variabel? Saya mengharapkan untuk melihat "jejak tikus" tetapi tidak dapat melihat, haha
justhalf
Sangat bagus, tetapi bukankah lebih masuk akal bahwa penunjuk harus naik di masa mendatang saat saat ini turun? Imho, program harus melakukan yang sebaliknya sehingga ia memprediksi pointer tetap di layar.
Madmenyo
@MennoGouw ini tidak sempurna tapi bagus sekali
NimChimpsky
@nimchimpsky Hanya mengatakan kemungkinan mouse naik lebih tinggi jika mouse saat ini turun. Program itu sendiri sangat bagus.
Madmenyo
Apakah Anda pikir itu juga mungkin untuk menggunakan perilaku manusia yang biasa untuk penanganan mouse? Seperti lingkaran, garis lurus ... Ini dapat diprediksi lebih jauh di masa depan (menghitung jari-jari lingkaran setelah beberapa pasangan, dan menyelesaikan lingkaran bahkan sebelum Anda menyusunnya)
Saffron
14

Jawa

Saya memutuskan untuk mengambil pendekatan mesin waktu. Ternyata bahan utama dari mesin waktu adalah java.awt.Robot. Program saya memungkinkan Anda menggerakkan mouse Anda selama 10 detik. Setelah 10 detik, ia kembali ke masa lalu dan menciptakan kembali gerakan mouse Anda, sambil memperkirakannya dengan sempurna.

masukkan deskripsi gambar di sini

Ini kodenya:

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

}
Rhubarb Custard
sumber
Kode sedikit dioptimalkan oleh Netbeans (menyingkirkan peringatan): pastebin.com/E57LZ4zY
Kaz Wolfe
10

Vanilla Javascript

Untuk memulainya, berikut adalah prediksi sederhana berdasarkan dua nilai. Posisi nmouse terakhir diingat dan disimpan dalam antrian, prediksinya adalah ekstrapolasi linear sederhana dari elemen pertama dan terakhir dalam antrian.

Ini hanya kode prediksi, kode lengkap termasuk demo dapat dilihat di 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;
}

Demo berisi komentar dalam prediksi yang memungkinkan Anda untuk menggunakan dua elemen terakhir dalam antrian untuk prediksi. Menjadikan hasilnya lebih "real-time", tetapi juga kurang "halus".

Jika ada yang ingin menggunakan boilerplate workuntuk menerapkan algoritma prediksi yang berbeda, silakan saja. Lagipula itu tidak banyak pekerjaan.

Ingo Bürk
sumber
Bisakah Anda menampilkan pointer mouse daripada garis? Saya mengharapkan untuk melihat "jejak tikus" tetapi tidak dapat melihat, haha
justhalf
Pertanyaannya mengatakan itu tidak harus menjadi kursor;)
Ingo Bürk
4

Javascript

Masa lalu adalah prediksi terbaik untuk masa depan - saya, dan mungkin juga orang lain

Solusi saya sangat sederhana. Pertama, ini dia >>> Fiddle! <<<

Yang dilakukannya hanyalah menggeser jejak masa lalu, jadi sepertinya jejak masa depan. Pada dasarnya tidak ada Matematika yang terlibat (Saya Tahu, sangat membosankan). Anda dapat dengan mudah melihat kesalahan, terutama saat memindahkan kursor dalam lingkaran. Itu sebabnya saya membuat jejak sangat singkat;)

Kode:

<!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
sumber
haha saya baru saja melihat tanggalnya. Terserah, saya suka
Felk