Воспроизведение в случайном порядке - PullRequest
2 голосов
/ 14 января 2011

Я программирую на Java, но я также мог бы принять C ++ (или даже псевдо) код, без проблем. Вот что я нахожусь:

У меня есть что-то вроде плейлиста, например List<MyPlayListItem> lsMyPlaylist. Теперь я хочу дать пользователю возможность перетасовать элементы, а затем вернуться к упорядоченному списку. Я имею в виду, скажем, пользователь находится в «режиме случайного воспроизведения», например, игрок. переходит от песни 7 к 5, но затем пользователь отключает «режим случайного воспроизведения», потому что он хочет услышать песню 6 дальше. Как бы вы подошли к этой проблеме?

У меня есть несколько идей:

  • для использования двух списков, один оригинал, один перетасованный (слишком много памяти)
  • есть список целых чисел, которые я перетасовываю, а затем использую в качестве индекса для получения элементов (возможно, немного лучше)
  • использовать хеш-таблицу (решение? Мне может понадобиться совет по этому поводу)

О, и это не домашнее задание (хотелось бы, чтобы я снова был в этом возрасте :-D).

EDIT:

Я только что закончил реализацию, как это:

PlayList<E> implements List {

   private List<E> lsObjs = null;
   private List<Integer> lsIdxs = null;

   boolean bShuffleMode = false;
   int Pos = 0;
}

Однако сейчас я думаю о чем-то вроде:

PlayListItem<E> {

   int iNextItem = 0;

}

PlayList<PlayListItem> implements List {

   private List<PlayListItem> lsObjs = null;

   boolean bShuffleMode = false;
   int Pos = 0;

}

Не уверен насчет этого ... Возможно, все еще нужен совет. Могу ли я реализовать Список, если я укажу объекты в списке? Хм ...

Ответы [ 6 ]

2 голосов
/ 15 января 2011

Как насчет добавления свойства nextSong на MyPlayListItem, которое будет содержать ссылку на следующую песню в оригинальном плейлисте.Каждый раз, когда пользователь перемешивает список воспроизведения, список будет перетасовываться, но исходный список воспроизведения будет сохраняться.Но, конечно, вам нужно что-то, чтобы содержать ссылку на первый MyPlayListItem в оригинальном плейлисте.

2 голосов
/ 14 января 2011

Я бы предложил иметь один основной контейнер для списка песен (Библиотека) и контейнер для списка воспроизведения.Конечно, список воспроизведения должен указывать на элементы в библиотеке.

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

Прошло много времени с тех пор, как я программировал на Java, поэтому приведу работающий пример C ++.Я надеюсь, что это просто и понятно:

// --*-- C++ --*--

#include <ctime>
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#include <list>

struct Song
{
    std::string name;

    Song (const std::string & name) :
        name (name)
    {
    }

    void play ()
    {
        printf ("Playing '%s'...\n", name.c_str ());
    }
};

typedef std::vector<Song> Library;
typedef std::vector<Song *> Playlist;
typedef std::vector<size_t> SongIDSet;

int
main ()
{
    srand (time (NULL));

    Library library;

    library.push_back (Song ("Lady Gaga - Bad Romance"));
    library.push_back (Song ("Rihanna - Only Girl"));
    library.push_back (Song ("Nelly - Just a Dream"));
    library.push_back (Song ("Animal - Neon Trees"));
    library.push_back (Song ("Eminem ft. Rihanna - Love The Way You Lie"));

    Playlist playlist;

    for (Library::iterator it = library.begin (),
             end_it = library.end (); it != end_it; ++it)
    {
        printf ("Added song -> %s\n", it->name.c_str ());
        playlist.push_back (&(*it));
    }

    SongIDSet shuffle;
    for (size_t i = 0, end_i = playlist.size (); i < end_i; ++i)
    {
        shuffle.push_back (i);
    }

    size_t nowPlaying = 0;

    while (!shuffle.empty ())
    {
        size_t songIndex = 0;
            printf ("Shuffle? [Y/n] ");
        switch (fgetc (stdin))
        {
            case 'N':
            case 'n':
                songIndex = nowPlaying + 1;
                fgetc (stdin); // Skip newline.
                break;
            case 'Y':
            case 'y':
                fgetc (stdin); // Skip newline.
            default:
            {
                printf ("Shuffling...\n");
                size_t index = rand () % shuffle.size ();
                assert (index >= 0);
                assert (index < shuffle.size ());
                songIndex = shuffle[index];
                shuffle.erase (shuffle.begin () + index);
            }
        }
        assert (songIndex >= 0);
        if (songIndex < playlist.size ())
        {
            nowPlaying = songIndex;
            playlist[nowPlaying]->play ();
        }
        else
        {
            break; // Done playing.. Repeat maybe?
        }
    }
}

Вот пример запуска / вывода:

$ ./test 
Added song -> Lady Gaga - Bad Romance
Added song -> Rihanna - Only Girl
Added song -> Nelly - Just a Dream
Added song -> Animal - Neon Trees
Added song -> Eminem ft. Rihanna - Love The Way You Lie
Shuffle? [Y/n] 
Shuffling...
Playing 'Eminem ft. Rihanna - Love The Way You Lie'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Nelly - Just a Dream'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Rihanna - Only Girl'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Animal - Neon Trees'...
Shuffle? [Y/n] 
Shuffling...
Playing 'Lady Gaga - Bad Romance'...
$ ./test 
Added song -> Lady Gaga - Bad Romance
Added song -> Rihanna - Only Girl
Added song -> Nelly - Just a Dream
Added song -> Animal - Neon Trees
Added song -> Eminem ft. Rihanna - Love The Way You Lie
Shuffle? [Y/n] 
S    huffling...
Playing 'Nelly - Just a Dream'...
Shuffle? [Y/n] n
Playing 'Animal - Neon Trees'...
Shuffle? [Y/n] n
Playing 'Eminem ft. Rihanna - Love The Way You Lie'...
Shuffle? [Y/n] n
2 голосов
/ 14 января 2011

Я предполагаю, что у вас есть мобильное устройство, у которого нет пары K для запаса. Наличие двух списков не будет дублировать элементы списка, который будет намного больше.

Добавление оригинального индекса в качестве поля в MyPlayListItem. После их перетасовки вы можете отсортировать их по индексу с помощью компаратора, чтобы вернуть их в исходный порядок. примечание: если индекс меньше 4 байт, он будет использовать столько же памяти, сколько два списка.

В 32-битной системе int [] и List занимают почти одинаковый объем памяти. (разница около 16 байтов)

1 голос
/ 14 января 2011

А как насчет чего-то простого?

Использовать указатель индекса в списке, скажем, целое число.Это текущая песня, которую играют.Когда игрок находится в режиме перемешивания, этот указатель устанавливается на случайное число от 0 до количества элементов в списке - 1. Когда игрок находится в последовательном режиме, этот указатель просто увеличивается.

ЕслиВы хотите предотвратить повторение песен, есть две стратегии.Одним из них является использование битовой строки, как предложил другой человек выше.Другой будет использовать набор.Каждый раз, когда указатель установлен, проверьте членство в наборе.Если он уже есть в наборе, получите другой индекс.Если это не так, то добавьте его и воспроизведите песню.Любой из них будет выполнять тот же эффект.

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

1 голос
/ 14 января 2011

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

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

0 голосов
/ 14 января 2011

У вас может быть два предмета:
1) список реальных предметов в списке
2) вектор с целочисленными индексами

Когда тасование активировано, вы тасуете индексы. Когда он выключен, сортируйте индексы. При доступе к элементам в списке используйте индексы.

как то так:

std::list< MyListElement > elements = ...;
std::vector< int > indexes = ...;

// shuffle off
sort( indexes.begin(), indexes.end() );

// get elements
elements[ indexes[ i ] ];
...