By adamlubek​
This recipe demonstrates RxJS implementation of Mine Sweeper Game.
​​​​
( StackBlitz )
// RxJS v6+import { fromEvent, of } from 'rxjs';import {map,tap,filter,pluck,switchMap,takeWhile,finalize} from 'rxjs/operators';import { renderMinefield, renderScore, renderGameOver } from './html-renderer';import { size, mine } from './constants';import { addMines, addMarks } from './mines';​const mines$ = of(Array(size).fill(0).map(e => Array(size).fill(0))).pipe(map(addMines), map(addMarks), tap(renderMinefield));​const click$ = mines =>fromEvent(document, 'click').pipe(map(({ clientX, clientY }: MouseEvent) =>document.elementFromPoint(clientX, clientY)),filter(elem => elem.id !== ''),tap(elem =>(val => (renderScore(val === mine || elem.innerHTML !== '_' ? 0 : val),(elem.innerHTML = val)))(mines[elem.id[0]][elem.id[1]])),pluck('id'),takeWhile(([x, y]) => mines[x][y] !== mine),finalize(renderGameOver));​mines$.pipe(switchMap(click$)).subscribe();
import { size, mine } from './constants';​const randomNumber = () => Math.floor(Math.random() * Math.floor(size));​export const addMines = arr => {for (let i = 0; i < size / 2; i++) {arr[randomNumber()][randomNumber()] = mine;}​return arr;};​const mark = (arr, x, y) =>arr[x] !== undefined && arr[x][y] !== undefined? (arr[x][y] += arr[x][y] === mine ? 0 : 1): () => {};​export const addMarks = arr => {for (let ri = 0; ri < size; ri++) {for (let ci = 0; ci < size; ci++) {if (arr[ri][ci] === mine) {mark(arr, ri - 1, ci + 1);mark(arr, ri - 1, ci);mark(arr, ri - 1, ci - 1);mark(arr, ri, ci + 1);mark(arr, ri, ci - 1);mark(arr, ri + 1, ci + 1);mark(arr, ri + 1, ci);mark(arr, ri + 1, ci - 1);}}}return arr;};
export const mine = 9;export const size = 10;
export const renderMinefield = arr =>arr.forEach((r, ri) =>(elem =>r.forEach((c, ci) =>(col => ((col.innerText = '_'),(col.id = `${ri}${ci}`),elem.appendChild(document.createTextNode('\u00A0\u00A0')),elem.appendChild(col)))(document.createElement('span')),document.body.appendChild(elem)))(document.createElement('div')));​export const renderScore = val =>(scoreElem => (scoreElem.innerText = parseInt(scoreElem.innerText) + val))(document.getElementById('score'));​export const renderGameOver = () =>(document.body.innerHTML += '<br/>GAME OVER');​const addElem = decorator =>(elem => (decorator(elem), document.body.appendChild(elem)))(document.createElement('span'));​addElem(elem => (elem.innerText = 'Score: '));addElem(elem => ((elem.id = 'score'), (elem.innerText = '0')));