First, find the pattern. Based on my findings, I have the following conclusion. Suppose I have five songs:

Let musics = [A, B, C, D, E, F] let musics = [A, B, C, D, E, F] // If the first round is over, the second round will also be random. If the first round is over, the second round will also be random. I test that the last song is the same as the next one, and it doesn't happen when I implement it // Based on this rule there are two ways: // 1) keep the first song clicked unchanged, the rest of the new array is randomly formed, and then execute according to the index step by step // 2) Select a random song from the original list that has not been played beforeCopy the code

I use this approach by first defining the class:

class RandomPlay {
  playList = [];
  currentPlayIndex = -1;
  size = 0;
  constructor(selectedMusic, allMusics) {
    this.playList.push(... this.randomMusics(selectedMusic, allMusics));this.size = allMusics? .length ||0;
    this.currentPlayIndex = this.size === 0 ? -1 : 0;
  }

  play = () = > {
    // Play the current song, throw if there is an error in the data
    if (this.currentPlayIndex < 0) {
      throw new Error("Playback error")}return this.playList[this.currentPlayIndex];
  };

  // To get a random list, the first parameter is to take care of the user's manually clicked track
  randomMusics = (selectedMusic, musics = [], isFount = false) = > {
    if (!Array.isArray(musics)) {
      return [];
    }
    const len = musics.length - 1;
    // Filter out the song that comes in
    const tempMusics = musics.filter((music) = >music ! == selectedMusic);for (let i = 0; i < len; i++) {
      // My random way is to swap randomly
      const index = Math.floor(Math.random() * (len - i) + i);
      let tempMusic = tempMusics[i];
      tempMusics[i] = tempMusics[index];
      tempMusics[index] = tempMusic;
    }
    // Use this field to determine whether the input is passed to the header or the tail
    if (isFount) {
      tempMusics.push(selectedMusic)
    } else {
      tempMusics.unshift(selectedMusic);
    }
    return tempMusics;
  };
  // The next track will no longer play the same song twice in a row, unlike the official one
  nextMusic = () = > {
    this.currentPlayIndex += 1;
    const len = this.playList.length;
    // If the play subscript is the same as the play array, the end is reached
    if (this.currentPlayIndex === len) {
      // Start by randomly selecting a song before the last one and place it in the next position, so that the next one will not appear before the last one
      const tempIndex = Math.random() * (this.size - 1) + (len - this.size)
      const index = Math.floor(tempIndex);
      // Add the newly generated song, so that the user clicks on the previous song
      this.playList.push(... this.randomMusics(this.playList[index], this.playList.slice(len - this.size)));
    }
    return this.playList[this.currentPlayIndex];
  };
  
  // In the last song, this place is different from the rule, I will modify the following
  lastMusic = () = > {
  	// If it is -1, there are no songs in the historical playlist
    this.currentPlayIndex -= 1;
    if (this.currentPlayIndex === -1) {
      // Array of random songs at the head of the playlist
      const tempIndex = Math.random() * (this.size - 2) + 1
      const index = Math.floor(tempIndex);
      this.playList.unshift(... this.randomMusics(this.playList[index],this.playList.slice(0.this.size), true));
      this.currentPlayIndex = this.size - 1;
    }
    return this.playList[this.currentPlayIndex]
  };
}
Copy the code