a generator that shuffles your 1D array via mutation, then yields randomly selected non-repeating elements out of it, one by one, until all elements have been yielded, at which a new cycle begins, and the items in the array are re-shuffled again. i.e. after every new cycle, the ordering of the randomly yielded elements will differ from the ordering of the previous cycle.

moreover, you can call the iterator with an optional number argument that specifies if you wish to skip ahead or go back a certain number of elements.

  • 1: go to next element (default behavior)
  • 0: receive the same element as before
  • -1: go to previous next element
  • +ve number: skip to next number of elements
  • -ve number: go back number of elements

note that once a cycle is complete, going back won't restore the correct element from the previous cycle, because the info about the previous cycle gets lost.

import { assert, assertEquals, assertNotEquals } from "jsr:@std/assert"

const
my_playlist = ["song1", "song2", "song3", "song4"],
my_queue = my_playlist.slice(),
track_iter = shuffledDeque(my_queue) // shuffles our play queue via mutation, and then indefinitely provides unique items each cycle

const
track1 = track_iter.next().value,
track2 = track_iter.next(1).value,
track3 = track_iter.next().value

assertEquals(track1, track_iter.next(-2).value)
assertEquals(track2, track_iter.next(1).value)
assertEquals(track3, track_iter.next().value)

const track4 = track_iter.next().value // final track of the current queue
const track5 = track_iter.next().value // the queue has been reset, and re-shuffled

assert([track1, track2, track3].includes(track4) === false)
assert([track1, track2, track3, track4].includes(track5) === true)