[Javascript] Broadcaster + Operator + Listener pattern -- 17. Building a Word Matching Game

It's common for a user to enter values that you want to check against your pre-defined values. Let's make a demo of a word game to demonstrate one approach to solving that use case.

Try consolidating map(hangmanLogic) even further into a stand-alone hangmanLogic operator so that there's no mapping, just the hangmanLogic operator

import { addListener, done, forOf } from "./broadcasters";
import { targetValue } from "./operators";

const log = console.log;

let inputInput = addListener("#input", "input");
let inputValue = targetValue(inputInput);

let word = forOf("honeycomb");

inputValue((value) => {
  let result = "";
  word((letter) => {
    if (letter === done) {
      console.log(result);
      return
    }
    if (value.includes(letter)) {
      result += letter;
    } else {
      result += "*";
    }
  });
});

/*
h**e***** 
honeycomb 
*/

We have outside 'inputValue' to provde value and inside 'word' providing innerValue.

 

1. Model the behavior for tow broadcasters: "inputValue" & "word".

The logic is "inputValue", inside, it doesn't mapping to a transform function but to another broadcaster: word.

So create a operator called mapBroadcaster:

let mapBroadcaster = createBroadcaster => broadcaster => listener => {
  broadcaster(value => {
    let newBroadcaster = createBroadcaster(value)
    newBroadcaster(listener)
  })
}

mapBroadcaster(value => word)(inputValue)(log)

 

2. Apply logic to inner broadcaster 'word':

logic we want to apply:

    if (value.includes(letter)) {
      result += letter;
    } else {
      result += "*";
    }

then:

let mapBroadcaster = (createBroadcaster) => (broadcaster) => (listener) => {
  broadcaster((value) => {
    let newBroadcaster = createBroadcaster(value);
    newBroadcaster(listener);
  });
};

mapBroadcaster((value) => {
  return map((letter) => (value.includes(letter) ? letter : "*"))(word);
})(inputValue)(log);

Equals to:

mapBroadcaster((value) => {
  return mapBroadcaster((operator) => operator(word))(
    map((value) => {
      return map((letter) => (value.includes(letter) ? letter : "*"));
    })(inputValue)
  );
})(log);

 

Pattern to catch: 

inputValue(value => logicFn)(listener)

// equals to 

map(value => logicFn)(inputValue)(listener)

 

Refect again:

let hangmanLogic = (value) => {
  return map((letter) => (value.includes(letter) ? letter : "*"));
};

mapBroadcaster((value) => {
  return mapBroadcaster((operator) => operator(word))(
    map(hangmanLogic)(inputValue)
  );
})(log);

 

3. Add helper function 'applyBroadcaster':

Catching this pattern:

mapBroadcaster((operator) => operator(word))

so:

let mapBroadcaster = (createBroadcaster) => (broadcaster) => (listener) => {
  broadcaster((value) => {
    let newBroadcaster = createBroadcaster(value);
    newBroadcaster(listener);
  });
};

let hangmanLogic = (value) => {
  return map((letter) => (value.includes(letter) ? letter : "*"));
};

let applyOperator = broadcaster => mapBroadcaster(operator => operator(broadcaster))

applyOperator(word)(
    map(hangmanLogic)(inputValue)
  )(log);

 

4. Apply "pipe":

let mapBroadcaster = (createBroadcaster) => (broadcaster) => (listener) => {
  broadcaster((value) => {
    let newBroadcaster = createBroadcaster(value);
    newBroadcaster(listener);
  });
};

let hangmanLogic = (value) => {
  return map((letter) => (value.includes(letter) ? letter : "*"));
};

let applyOperator = (broadcaster) =>
  mapBroadcaster((operator) => operator(broadcaster));

let hangman = pipe(map(hangmanLogic), applyOperator(word));
hangman(inputValue)(log);

 

 

5. Applying the rest of logic:

let mapBroadcaster = (createBroadcaster) => (broadcaster) => (listener) => {
  broadcaster((value) => {
    let newBroadcaster = createBroadcaster(value);
    newBroadcaster(listener);
  });
};

let hangmanLogic = (value) => {
  return map((letter) => (value.includes(letter) ? letter : "*"));
};

let applyOperator = (broadcaster) =>
  mapBroadcaster((operator) => operator(broadcaster));

let stringConcat = (broadcaster) => (listener) => {
  let result = "";
  broadcaster((value) => {
    if (value === done) {
      listener(result);
      result = "";
      return;
    }
    result += value;
  });
};

let hangman = pipe(map(hangmanLogic), applyOperator(word), stringConcat);
hangman(inputValue)(log);

 


 

Full code:

import { addListener, done, forOf } from "./broadcasters";
import { targetValue, map } from "./operators";
import { pipe } from "lodash/fp";
const log = console.log;

let inputInput = addListener("#input", "input");
let inputValue = targetValue(inputInput);

let word = forOf("honeycomb");

inputValue((value) => {});

let mapBroadcaster = (createBroadcaster) => (broadcaster) => (listener) => {
  broadcaster((value) => {
    let newBroadcaster = createBroadcaster(value);
    newBroadcaster(listener);
  });
};

let hangmanLogic = (value) => {
  return map((letter) => (value.includes(letter) ? letter : "*"));
};

let applyOperator = (broadcaster) =>
  mapBroadcaster((operator) => operator(broadcaster));

let stringConcat = (broadcaster) => (listener) => {
  let result = "";
  broadcaster((value) => {
    if (value === done) {
      listener(result);
      result = "";
      return;
    }
    result += value;
  });
};

let hangman = pipe(map(hangmanLogic), applyOperator(word), stringConcat);
hangman(inputValue)(log);

 

posted @ 2020-11-12 15:56  Zhentiw  阅读(136)  评论(0编辑  收藏  举报