Shuffle That Playlist – Solution

The solution to this month’s Exercise is similar to code I’ve presented in my books and in this blog with regards to randomly drawing from a fixed set of elements. Yet it has an extra level of complexity.

In those examples, the goal is to not draw the same lotto ball or card from a deck twice. You can’t do that in real life, so you must replicate this restriction in your code. To do so, you create an array or other method that monitories which items can no longer be drawn.

For example, with a deck of cards you create a 52-element int array where each element number is the card. The array element values are either 1 or 0 depending on whether a card (element number) is drawn.

When implementing a random song playlist, you must ensure that the same tune doesn’t play twice within a given range. If the entire list of tunes are shuffled alone, the solution to the Exercise would be identical to the Lotto program given in my books: Play a song once, flag it as played, then don’t play it again. But in this Exercise the playlist repeats, playing up to 100 instances of the variety of 20 tunes. Still, the solution is similar.

To the sample code presented in the Exercise, I add a recent[] array. This array, like the array for a deck of cards or lotto balls, keeps track of the tunes played:

int recent[COUNT];

The size of the array is the same as the amount of tunes, COUNT (or 20). It could be 15, which is the limit during which no tune can play twice, but I chose 20 so that the array could be initialized at the same time as the frequency[] array:

for(t=0;t<COUNT;t++)
{
    frequency[t] = 0;
    recent[t] = COUNT+1;
}

The first statement in the for loop initializes the frequency[] array, setting all elements to zero. The second line initializes the recent[] array to the value COUNT+1. This value is higher than any element number in the tune[] array.

Variable play holds a random value, 0 to 19, indicating which tune to play. Before the tune is played, the contents of the recent[] array are scanned to see if that tune/number has played recently:

do
{
    play = rand() % COUNT;
    found = 0;
    for(t=0;t<RANGE;t++)
    {
        if(recent[t]==play)
        found=1;
    }
} while(found);

When the value of play is stored within RANGE (15) elements of array recent[], the found flag is set. If so, the while loop repeats, fetching another random number for play. Only when play doesn’t appear within the first RANGE elements of the recent[] array does the loop stop.

After the code is certain that the play value is fresh, the tune is “played” and its title output.

Next, a for loop shifts the values in the recent[] array:

for(t=COUNT-1;t>0;t--)
{
    recent[t] = recent[t-1];
}
recent[0] = play;

Each element is replaced by the preceding element. So element 18 becomes 19, and so on. After the elements are shifted, the most recent tune played is added at the start of the list. This technique is how the code keeps track of recent songs played.

Click here to view the full code. Here’s the tail part of the output:

...
Playing 99: Call Me
Playing 100: My Sharona
Play Frequency:
Brandy, 5
Respect, 5
Hey Jude, 4
The Twist, 5
Uptown Funk, 5
Macarena, 5
Killer Queen, 5
Lady, 5
Foolish Games, 5
Call Me, 6
Royals, 6
The Sign, 6
Happy, 6
Billie Jean, 5
My Sharona, 6
Family Affair, 5
Hurts So Good, 4
Smooth, 4
Mack The Knife, 4
No One, 4

Unlike the example shown in the Exercise post, the play frequency results show values of 4, 5, and 6. This means the tunes are distributed relatively evenly throughout the 100 plays. Reviewing the detailed output shows that no two songs are played back-to-back — or within 15 tunes of itself.

I hope that you were also able to devise a clever and workable solution to the puzzle. This challenge was more nerdy that most, which is good when you must exercise your C language kung fu.

Leave a Reply