Learn RxJS
Search…
Memory Game
By adamlubek
This recipe demonstrates an RxJS game to train your memory.

Example Code

Memory Game

index.ts

1
// RxJS v6+
2
import { EMPTY, from, fromEvent, generate, interval, merge, noop } from 'rxjs';
3
import {
4
map,
5
pluck,
6
scan,
7
sequenceEqual,
8
switchMap,
9
take,
10
tap
11
} from 'rxjs/operators';
12
13
const random = (): number => Math.floor(Math.random() * Math.floor(8));
14
const setInfo = (text: string) =>
15
(document.getElementById('info').innerHTML = text);
16
const displayLevelChange = () =>
17
document
18
.querySelectorAll('.child')
19
.forEach((c: HTMLElement) => (c.style.background = 'gray'));
20
21
const checkIfGameOver$ = (randomSequence: number[]) => (
22
userSequence: number[]
23
) =>
24
from(userSequence).pipe(
25
sequenceEqual(from(randomSequence)),
26
tap(match =>
27
!match && userSequence.length === randomSequence.length
28
? setInfo('GAME OVER!')
29
: noop
30
)
31
);
32
33
const takePlayerInput$ = (randomSequence: number[]) => _ =>
34
fromEvent(document, 'click').pipe(
35
take(randomSequence.length),
36
scan(
37
(acc: number[], curr: MouseEvent) => [
38
...acc,
39
parseInt(curr.target['id'])
40
],
41
[]
42
),
43
switchMap(checkIfGameOver$(randomSequence)),
44
switchMap(result =>
45
result
46
? (displayLevelChange(), memoryGame$(randomSequence.length + 1))
47
: EMPTY
48
)
49
);
50
51
const showSequenceToMemorize$ = (memorySize: number) => (
52
randomSequence: number[]
53
) =>
54
interval(1000).pipe(
55
tap(i =>
56
setInfo(i === memorySize - 1 ? `YOUR TURN` : `${memorySize - i} elements`)
57
),
58
take(randomSequence.length),
59
map(index => randomSequence[index]),
60
tap(value => document.getElementById(`${value}`).click()),
61
switchMap(takePlayerInput$(randomSequence))
62
);
63
64
const memoryGame$ = memorySize =>
65
generate(
66
1,
67
x => x <= memorySize,
68
x => x + 1
69
).pipe(
70
scan((acc: number[], _: number): number[] => [...acc, random() + 1], []),
71
switchMap(showSequenceToMemorize$(memorySize))
72
);
73
74
const elementClick$ = (event: string, color: string) =>
75
fromEvent(document.querySelectorAll('.child'), event).pipe(
76
pluck('srcElement'),
77
tap((e: HTMLElement) => (e.style.background = color))
78
);
79
80
const clicks$ = merge(
81
elementClick$('click', 'lightgray'),
82
elementClick$('transitionend', 'white')
83
);
84
85
const game$ = merge(clicks$, memoryGame$(2));
86
87
game$.subscribe();
Copied!

index.html

1
<style>
2
.parent {
3
border-spacing: 5px;
4
width: 50%;
5
padding: 0.5em;
6
}
7
8
.parent.perspective {
9
perspective: 50em;
10
}
11
12
.child {
13
margin: 0.5em;
14
max-width: 2em;
15
min-width: 2em;
16
height: 2.8em;
17
padding: 0.5em;
18
display: table-cell;
19
border: 1px solid rgba(0, 0, 0, 0.5);
20
}
21
22
.parent.perspective .child {
23
transform: rotateX(40deg);
24
transition: all 0.3s ease-in;
25
}
26
</style>
27
28
<div id="info">Train Your Memory!</div>
29
<div id="grid" class="grid parent perspective">
30
<div>
31
<div class="child" id="1"></div>
32
<div class="child" id="2"></div>
33
<div class="child" id="3"></div>
34
</div>
35
<div>
36
<div class="child" id="4"></div>
37
<div class="child" id="5"></div>
38
<div class="child" id="6"></div>
39
</div>
40
<div>
41
<div class="child" id="7"></div>
42
<div class="child" id="8"></div>
43
<div class="child" id="9"></div>
44
</div>
45
</div>
Copied!

Operators Used

Last modified 1yr ago