Home > Mobile >  Generator Functions: Conditionally yield result of another generator
Generator Functions: Conditionally yield result of another generator

Time:09-18

There was a question here recently (which I can't find) that had a die roll problem that posed an interesting condition:

Roll three die, and generate a color value that represented their position of each entity rolling a die (in order to provide a background-color). green for "winner", yellow for 2nd place, red for 3rd place and blue for draw.

[EDIT]: Initially I created a Class with a generator function like this, where the inner generator terminated after the first time it was used (thanks @Pointy)

    class Event {
      ...
      
      * generateColor() {
        let color = this.single.next() // potential discard
        while (this.result > 1) {
          yield "blue"
        }
        yield color.value
      }

Current iteration looks like this.

class Event {
  constructor(description) {
    if (description) {
      console.log(description)
      this.description = description
    }
    this.result = null
    this.generator = this.generateColor()
  }

  * singleColor() {
    yield "green"
    yield "yellow"
    yield "red"
  }
  
  * generateColor() {
    while (this.result > 1) {
      yield "blue"
    }
    yield* this.singleColor()
  }
  
  getColor(result) {
    this.result = result
    return this.generator.next()
  }
}

let event = new Event('three different rolls')
console.log(event.getColor(1))
console.log(event.getColor(1))
console.log(event.getColor(1))

event = new Event('one high roll, two draws')
console.log(event.getColor(1))
console.log(event.getColor(2))

event = new Event('two draws, one low roll')
console.log(event.getColor(2))
console.log(event.getColor(1))

event = new Event('three draws')
console.log(event.getColor(3))

The expected results are:

green, yellow, red
green, blue
blue, yellow
blue

However results being generated are:

green, yellow, red
green, yellow
blue, green
blue

How can this be corrected?

CodePudding user response:

It seems you want to consume any way the singleColor() values, but have them overruled by "blue" when the result property is greater than 1.

In your implementation however:

  • your code is not generating those singleColor() values until the result property has been set to one. No progress is made in that iterator while "blue" is being yielded, so that "blue" is not replacing any color from singleColor(). It merely is a prelude series of "blue" before the complete singleColor() sequence is started.

  • Once the singleColor() iteration starts, the value of the result property no longer has an influence on this -- no more "blue" is produced.

To change that behaviour, make sure you iterate the singleColor() colors from the start, and then check in each iteration the result property to decide whether that value or its "blue" replacement is yielded.

Implementation:

class Event {
  constructor(description) {
    if (description) {
      console.log(description);
      this.description = description;
    }
    this.result = null;
    this.generator = this.generateColor();
  }

  * singleColor() {
    yield "green";
    yield "yellow";
    yield "red";
  }

  * generateColor() {
    while (true) {
      for (let color of this.singleColor()) {
        yield this.result > 1 ? "blue" : color;
      }
    }
  }

  getColor(result) {
    this.result = result;
    return this.generator.next().value;
  }
}

let event = new Event('three different rolls')
console.log(event.getColor(1))
console.log(event.getColor(1))
console.log(event.getColor(1))

event = new Event('one high roll, two draws')
console.log(event.getColor(1))
console.log(event.getColor(2))

event = new Event('two draws, one low roll')
console.log(event.getColor(2))
console.log(event.getColor(1))

event = new Event('three draws')
console.log(event.getColor(3))

  • Related