Тест-тренировка зрительного внимания

Если я напишу 2, потом 4, потом 6, тогда мы почувствуем себя хорошо, потому что мы знаем, что дальше идет 8. Мы можем это предвидеть, мы не в руках судьбы. Однако, к сожалению, это не имеет ничего общего с истиной…
х/ф «Оксфордские убийства»


9a395bf99a8142daa0629df1a76d2f28.png
Задача: обнаружить центральную фигуру среди сереньких фигур вокруг.

Данный проект — PsyMatchArea — задумывался в качестве альтернативы знаменитым таблицам Шульте. С теми же целями (тренировка зрительного периферического внимания), но с другими, более «отмороженными» исходными предпосылками. Во-первых, нужно было уйти от цифр и букв — символов, знакомых каждому практически с яслей и потому распознаваемых на автомате без активного вовлечения сознания в процесс. Во-вторых, чтобы внимание как можно меньше подменялось памятью (и вообще не расслаблялось), надо было обеспечить соответствующие «помехи» — смена позиций, мерцания, наложения и т.п.

Режим с несколькими одновременно включёнными помехами
93c16542e0904cf4a444a07a6b93c9d3.gif


Самым, наверное, интересным с точки зрения программирования было создать алгоритм, который бы выдавал достаточно разнообразное множество абстрактных символов того или иного типа. Например, символы типа «руна» выращиваются следующим образом: алгоритму на входе предлагается сгенерировать в узловой матрице 3×3 пять последовательных соединений с некоторыми топологическими «принуждениями» (ограничение на количество пересечений и повышенная вероятность зацепа всех сторон периметра матрицы). Если в течение определённого количества попыток алгоритм заходит в тупик, он проявляет «толерантность» и пропускает к выходу последний тупиковый вариант (как говорится, что выросло, то выросло).

Код генератора рун
void CRunePattern::genSolidLink(int linkCount, int crossesCount)
{
    if (this->isEmpty())
        return;
    int broadCharge = 5;
    while (broadCharge) {
        m_links.clear();
        QVector  dots;
        int currDot = qrand()%(m_cols*m_rows);
        for (int i = 0; i < linkCount; ++i)
        {
            dots.append(currDot);
            int crossCharge = 5;
            while (crossCharge) {
                int nextDotCharge = 5;
                int nextDot = qrand()%(m_cols*m_rows);
                while (nextDotCharge && dots.contains(nextDot)) {
                    nextDot = qrand()%(m_cols*m_rows);
                    nextDotCharge --;
                }
                if (nextDotCharge) {
                    CDotLink newLink = CDotLink(currDot, nextDot);
                    if (this->hasCrossLink(newLink)) {
                        if (crossesCount) {
                            crossesCount --;
                        } else {
                            // find another link that is'nt crosses with others
                            crossCharge --;
                            continue; 
                        }
                    }
                    m_links.append(newLink);
                    currDot = nextDot;
                }
                break;
            }
        }
        int maxRow = -1;
        int minRow = m_rows;
        int maxCol = -1;
        int minCol = m_rows;
        for (int d = 0; d < dots.count(); ++d) {
            if (rowByDot(dots.at(d)) < minRow)
                minRow = rowByDot(dots.at(d));
            if (rowByDot(dots.at(d)) > maxRow)
                maxRow = rowByDot(dots.at(d));
            if (colByDot(dots.at(d)) < minCol)
                minCol = colByDot(dots.at(d));
            if (colByDot(dots.at(d)) > maxCol)
                maxCol = colByDot(dots.at(d));
        }
        if (minCol == 0 && minRow == 0 && 
            maxRow == m_rows - 1 && maxCol == m_cols - 1)
            break;
        broadCharge --;
        continue;
    }
}


На данный момент программа способна генерировать знаки нескольких типов:
ad2c88e2802644a0b388fe48b1ae6b76.png

Так же были реализованы следующие помехи:

  • Swap interference — перетасовка фигур
  • Hide center pattern — исчезновение центральной фигуры
  • Thrill interference — дребезжание фигур
  • Color interference — цветовое мерцание (гирлянда)
  • Cover interference — концентрические окружности


Кроме того, предусмотрена возможность включения подсказки — Tip Settings (искомая фигура «подсвечивается» через указанное время).

Интерфейс настроек
4fe160b271784146be50de97988870c1.png


После прохождения таблицы показывается статистика. По горизонтали угадывания, по вертикали время. Зелёный цвет — правильный ответ, красный — неверный, жёлтый — была подсказка.

Отображение статистики
422c71b2e6fe4803b2a7abe59e5c6d52.png


Пара методических замечаний. Не стоит искать фигуру, разбрасывая взгляд во всех направлениях — это, во-первых, быстро вымотает и, во-вторых, ничего не даст в плане развития фонового внимания. Желательно расслабиться и рассредоточить локус зрительного внимания по всему окну, держа «в уме» искомую фигуру.

Исходный код на GitHub (Qt 4.8)
Сборка под Win32

© Habrahabr.ru