How to detect konami code with Rx.js (reactive extensions for javascript)?
Asked Answered
S

3

8

I want to start learning Rx.js and I'm looking for a cool example to start the ball rolling. How do I detect konami code with Rx.js?

I want to detect a sequence of key press events (up up down down left right left right B A) and display an image if this happens.

Stability answered 2/12, 2010 at 15:31 Comment(0)
S
7

Here is my version:

<html>
<head>
<script type="text/javascript" src="jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="rx.js"></script>
<script type="text/javascript" src="rx.jQuery.js"></script>
</head>
<body>
<p id="result"></p>
<script type="text/javascript">
    $(function() {
        var konami = $(document).toObservable("keyup").Select(function(e) {
            return e.keyCode
        }).SkipWhile(function(k) {
            return (k != 38)
        }).BufferWithCount(
            10
        ).Where(function(ks) {
            return ks.length == 10 &&
                ks[0] == 38 && ks[1] == 38 &&
                ks[2] == 40 && ks[3] == 40 &&
                ks[4] == 37 && ks[5] == 39 &&
                ks[6] == 37 && ks[7] == 39 &&
                ks[8] == 66 && ks[9] == 65
        })

        var konamisub = konami.Subscribe(function(e) {
            $("#result").text("KONAMI!")
            $("#result").fadeIn().fadeOut()
        })
    })
</script>
</body>
</html>

I convert the stream of keyup events into a stream of keycodes with the Select, then ignoring keypresses until the user press up (keycode 38) with the SkipWhile, then collecting 10 keystrokes with the BufferWithCount, then checking the keystrokes with the Where.

I tried using BufferWithTime, but it tends to cut in the middle of keystrokes.

If somebody can suggest improvements, I would love to hear them.

Stability answered 8/12, 2010 at 15:31 Comment(1)
This Rx.js Konami code example on github looks to be idiomatic. Looks like they're using conventional JS function naming now (no initial upper-case).Tattoo
S
1

I don't want to spoil the answer for you since you're learning, but I would try to think of the problem as, "How can I transform the Key up event into the sequence of the last 10 characters that were recently pressed", and compare that list to the constant list of "UUDDLRLRBA". (Hint: Buffer, Where, Select, Take, Repeat are your friends here)

Sallysallyann answered 8/12, 2010 at 5:25 Comment(2)
Actually I don't mind spoilers :) but yes it wouldn't be as much fun. Thanks for the hint!Stability
I got it working, but it doesn't use Take nor Repeat. How would you use Take and Repeat in this scenario?Stability
W
0

To update the answer from Endy (in RxJS 7) (with sequenceEqual from rxjs sample, because, smart usage of it :D)

const table: {[key: string]: number} = {
    ArrowUp: 38,
    ArrowDown: 40,
    ArrowLeft: 37,
    ArrowRight: 39,
    KeyB: 66,
    // Azerty compat
    KeyQ: 65,
    KeyA: 65,
};

const knownSequence = from([38, 38, 40, 40, 37, 39, 37, 39, 66, 66]);

const konami$ = fromEvent<KeyboardEvent>(document, 'keyup').pipe(
    map((e) => table[e.code] ? table[e.code] : -1),
    skipWhile((k) => k !== 38),
    bufferCount(10, 1),
    mergeMap((x) => {
        return from(x).pipe(sequenceEqual(knownSequence));
    }),
    filter((sequenceEqual) => sequenceEqual),
    switchMap((_) => of('konami'))
);

// Basic usage (promisified)
await firstValueFrom(konami$);
// Do Konami thing
Waldemar answered 5/9, 2022 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.