Algorytm wyszukiwania w tablicy

0

Dzień dobry,

Napisałem nieporadnie taką oto funkcję. Funkcja zwraca numer progu i numer struny na gitarze, po kliknięciu w odpowiednie miejsce na podstrunnicy. Jednym słowem zamienia współrzędne myszki po kliknięciu, na współrzędne na gryfie gitary (nr struny i progu). Niestety ma ona 2 wady:

  • źle wygląda
  • nie działa do końca tak, jak po testowaniu doszedłem do wniosku.

Mianowicie teraz, funkcja wybiera próg, względem którego najbliżej nastąpiło kliknięcie. To jednak nie jest dla gitarzysty intuicyjne, bo, jak każdy kto gra na gitarze wie, wystarczy docisnąć strunę przed danym progiem i już uzyska się dany dźwięk.

Podsumowując, jak można napisać (wskazówki ;) ) algorytm, który będzie zwracał próg n, jeżeli kliknięcie było 10px lub więcej za n-1 progiem, jednak nie więcej niż 10px za progiem n.

function getClickedNoteFromC(x, y) {
    var startX = 0; // posta struna
    var startY = 0; // struna 6
    var endX = 13; // za 12 progiem (max 12 progów)
    var endY = 6; // przed struną 1
    var diff = 10000; // początkowa odległość między kliknięciem a współrzędną progu
    var times = 0; // jakby algorytm się zapętlił, to pętla wykona się max 5x
    var result = []; // wynik
    while (true) {
        var actXPlus  = parseInt((endX + startX) / 2); // dzielimy przedział na 2
        var newDiff = x - xy[0][actXPlus]; // odległość między współrzędną x (argument), a współrzędną progu

        if (diff > Math.abs(newDiff)) { // jeśli nowa odległość jest mniejsza, podmieniamy ją z zapisaną i zmieniamy wynik
            diff = Math.abs(newDiff);
            result[0] = actXPlus;
        }

        if (newDiff < 0) // zawężamy przedział
            endX = actXPlus;
        
        else if (newDiff > 0) // zawężamy przediał
            startX = actXPlus;
        
        else { // bingo, ale to się rzadko zdaża
            result[0] = actXPlus;
            break;
        }
        
        if (startX == endX) // kończymy pętlę
            break;

        if ((startX + 1) == endX) // odliczamy
            times += 1;
        
        if (times > 5) // jak odliczyliśmy ponad 5, kończymy
            break;
        
        console.log(1, actXPlus, newDiff, diff, startX, endX, times);
    }

    diff = 10000;
    times = 0;

    while (true) { // to samo dla y, tyle, że y są posortowane malejąco w tablicy
        var actYPlus  = parseInt((endY + startY) / 2);
        var newDiff = xy[1][actYPlus] - y; // tu różnica, (malejące sortowanie)

        if (diff > Math.abs(newDiff)) {
            diff = Math.abs(newDiff);
            result[1] = actYPlus;
        }

        if (newDiff < 0)
            endY = actYPlus;
        
        else if (newDiff > 0)
            startY = actYPlus;
        
        else {
            result[1] = actYPlus;
            break;
        }
        
        if (startY == endY)
            break;

        if ((startY + 1) == endY)
            times += 1;

        if (times > 5)
            break;

        console.log(2, actYPlus, newDiff, diff, startY, endY, times);
    }

    return result;
}

wiem, że mógłbym się nie bawić i napisać na pałę sprawdzanie wszystkiego po kolei, w końcu tablica jest tylko [6][13], ale chcę się nauczyć optymalnego podejścia.

Dziękuję
M.

0

Poprawiłem

function getClickedNoteFromC2(x, y) {
    var startX = 0;
    var startY = 0;
    var endX = 13;
    var endY = 6;
    var result = [];
    var times = 5;

    while (true) {
        var actXPlus  = parseInt((endX + startX) / 2);

        if (x <= xy[0][actXPlus] + 10) {
            if (actXPlus == 0) {
                result[0] = 0;
                break;
            }
                
            if (x > xy[0][actXPlus - 1]) {
                result[0] = actXPlus;
                break;
            }

            endX = actXPlus;
        }

        else
            startX = actXPlus;
        
        if (endX - startX == 1) {
            times -= 1;

            if (times == 0) {
                result[0] = actXPlus;
                break;
            }
        }
        console.log(1, x, actXPlus, startX, endX);
    }

    times = 5;

    while (true) {
        var actYPlus  = parseInt((endY + startY) / 2);

        if (y >= xy[1][actYPlus] + 10) {
            if (actYPlus == 0) {
                result[1] = 0;
                break;
            }
                
            if (y < xy[1][actYPlus - 1] - 10) {
                result[1] = actYPlus;
                break;
            }

            endY = actYPlus;
        }

        else
            startY = actYPlus;

        if (endY - startY == 1) {
            times -= 1;

            if (times == 0) {
                result[1] = actYPlus;
                break;
            }
        }
        console.log(2, y, actYPlus, startY, endY);
    }

    return result;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1