Показать указатель мыши тропы ... о будущем!


24

Вдохновленный этим примером использования d3js , я призываю вас создать холст (или ваш эквивалент по выбору языка), в котором будут отображаться следы указателя мыши со следующим поворотом:

Твист

Вы не должны показывать следы , где указатель мыши был , но «следы» , где она будет (может) быть в будущем.

Вы можете сделать это с помощью:

  1. Машина времени или

  2. Вероятностные оценки, основанные на предыдущих движениях мыши

Предположения

Если вы не выбрали реализацию машины времени, когда мышь не двигается более пороговых миллисекунд, вы не можете отобразить ни один из следов. ( Пороговое значение зависит от вас, чтобы выбрать).

Изображение курсора зависит от вас и не обязательно должно совпадать с курсором ОС (вы даже можете нарисовать простые маленькие кружки или точки).

Никакой злой вклад не будет проверен: вы можете считать, что движения плавные. «Гладкое» определение для этого случая: если бы движения мыши были функцией по осям x и y холста - это была бы непрерывная функция.

выигрыш

Действительный ответ с наименьшим количеством символов в коде победит. В случае ничьей победит тот, кто был размещен первым.

РЕДАКТИРОВАТЬ: победит действительный ответ с наибольшим количеством голосов . В случае ничьей победит тот, кто был размещен первым. Вы можете быть креативным в реализации или быть точным с предсказанием. Я больше не судья, мы все такие :)

  • Действительный ответ должен включать в себя способ игры (тест! Я имел в виду тест), либо с помощью онлайн-инструмента, либо с помощью свободно загружаемого компилятора / интерпретатора / среды выполнения / и т.д.

2
Я думаю, что этот вопрос лучше подходит для конкурса популярности, чем для игры в гольф, потому что он довольно субъективен в отношении того, что считается достаточно хорошим прогнозом. Я бы рекомендовал уточнить это или изменить тег. Тем не менее, выглядит весело.
Исаак

2
Вы правы. Я отредактировал вопрос и изменил тег.
Джейкоб

Время для кого-то, чтобы реализовать алгоритмы машинного обучения!
Инго Бюрк

6
Для целей тестирования, к каким моделям машины времени у вас есть доступ? И можем ли мы использовать стандартные библиотеки для взаимодействия с ними?
Питер Тейлор

1
Просто математик скулит здесь: гладко! = Непрерывно. На самом деле движение дикого шипика все еще будет непрерывным.
CompuChip

Ответы:


33

Javascript

Моя программа предсказывает направление указателя, используя среднее угловое изменение в направлении последних 20 движений мыши. Он также использует дисперсию углового изменения для создания «облака» возможных местоположений и направлений указателя. Предполагается, что цвет каждого указателя в «облаке» представляет вероятность того, что он является новой позицией указателя мыши, в то время как более темные цвета представляют большую вероятность. Расстояние до облака указателя впереди мыши рассчитывается с использованием скорости движения мыши. Это не делает лучшие прогнозы, но выглядит аккуратно.

Вот скрипка: http://jsfiddle.net/5hs64t7w/4/

Увеличение размера облака указателя интересно посмотреть. Это может быть установлено путем изменения cloudSizeпеременной в первой строке программы. Вот скрипка с облаком размером 10: http://jsfiddle.net/5hs64t7w/5/

Я использовал эти источники, чтобы получить формулы для кругового среднего и дисперсии:
Круговое среднее: http://en.wikipedia.org/wiki/Circular_mean
Круговое отклонение: http://www.ebi.ac.uk/thornton-srv/software/ ProCheck / nmr_manual / man_cv.html

Вот код, если кому-то интересно:

    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
Можете ли вы отобразить последовательность указателя мыши (с фиксированной ориентацией) вместо указателя, указывающего на переменное направление? Я ожидал увидеть "следы мыши", но не вижу ничего, ха-ха
justhalf

Очень хорошо, но не более ли правдоподобно, что указатель должен увеличиваться в будущем, когда он в настоящее время идет вниз? Имхо, программа должна делать с точностью до наоборот, поэтому она предсказывает, что указатель остается на экране.
Madmenyo

@MennoGouw не идеален, но чертовски хорош
NimChimpsky

@nimchimpsky Просто сказать, что вероятность поднятия мыши выше, если мышь в данный момент идет вниз. Сама программа отличная.
Madmenyo

Как вы думаете, также возможно использовать обычное поведение человека для работы с мышью? Как круги, прямые линии ... Это может быть предсказано еще дальше в будущем (вычисление радиуса круга после пары заездов и завершение круга еще до того, как вы его составили)
Шафран

14

Джава

Я решил использовать подход машины времени. Оказывается, ключевым компонентом машины времени является java.awt.Robot. Моя программа позволяет перемещать мышь в течение 10 секунд. Через 10 секунд он возвращается во времени и воссоздает движение мыши, в то же время прекрасно предсказывая.

введите описание изображения здесь

Вот код:

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

}

Netbeans немного оптимизировал код (избавился от предупреждений): pastebin.com/E57LZ4zY
Kaz Wolfe

10

Ванильный Javascript

Просто для начала, вот простое предсказание, основанное на двух значениях. Последние nпозиции мыши запоминаются и хранятся в очереди, прогноз - простая линейная экстраполяция первого и последнего элемента в очереди.

Это просто код предсказания, полный код, включая демонстрацию, можно увидеть в 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;
}

Демонстрация содержит комментарий в прогнозе, который позволяет вместо этого использовать два последних элемента в очереди для прогнозирования. Делает результат более «в реальном времени», но также и менее «гладким».

Если кто-то хочет использовать boilerplate workдля реализации другого алгоритма прогнозирования, не стесняйтесь. Это не так много работы в любом случае.


Вы можете отобразить указатель мыши вместо линии? Я ожидал увидеть "следы мыши", но ничего не вижу, ха-ха
justhalf

Вопрос говорит, что это не обязательно должен быть курсор;)
Инго Бюрк

4

Javascript

Прошлое - лучший прогноз на будущее - я и, возможно, кто-то еще

Мое решение очень простое. Во-первых, это >>> Скрипка! <<<

Все, что он делает, это смещает прошлый след, так что он выглядит как будущий след. В основном, нет математики (я знаю, довольно скучно). Вы можете легко увидеть ошибки, особенно при перемещении курсора по кругу. Вот почему я сделал след так коротким;)

Код:

<!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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.