[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);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2019-11-12 [Go] Slices vs Array
2015-11-12 [AngularJS] ng-if vs ng-show
2015-11-12 [ES6] Array.find()
2015-11-12 [ES6] Array.findIndex()
2015-11-12 [Javascript] Object.assign()
2014-11-12 [Unit Testing for Zombie] 06. Using Factory
2014-11-12 [Node.js] Level 5. Express