MapleStory RPS Helper

Recode of agrodesu's MapleStory RPS Helper. https://agrodesu.com/maple/RPS/

by MegaScience

HTML

<h1>Maplestory RPS Helper</h1>
<div id="container">
    <div id="roundBody">Round: <span id="currentRound">1</span>/9</div>

    <section style="margin-top: -24px;">
        <h2>Suggestion</h2>
        <div id="suggestion">
            <img alt="ROCK" id="suggestedRock" draggable="false">
            <img alt="PAPER" id="suggestedPaper" draggable="false">
            <img alt="SCISSORS" id="suggestedScissor" draggable="false">
        </div>
        <div id="reason">Reason: Odds of each result are EQUAL.</div>
    </section>

    <section>
        <h2>Kemdi's Picks</h2>
        <div id="picks">
            <div id="kemdiRock">
                <img lt="ROCK" draggable="false">
                <div class="remaining">3</div>
            </div>
            <div id="kemdiPaper">
                <img alt="PAPER" draggable="false">
                <div class="remaining">3</div>
            </div>
            <div id="kemdiScissor">
                <img alt="SCISSORS" draggable="false">
                <div class="remaining">3</div>
            </div>
        </div>
        <div id="instructions">Click the one that Kemdi picked this round.</div>
    </section>

    <section id="restartSection" class="hide">
        <button id="restartButton">Restart</button>
    </section>
</div>

CSS

body {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  background:...

JavaScript

const rpsLib = {
    s: {
        index: {
            rock: ['scissor', 'paper'],
            paper: ['rock', 'scissor'],
            scissor: ['paper', 'rock']
        }
    },
    // https://stackoverflow.com/a/14810722
    objectMap: (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)])),
    capitalCase: ([f, ...r], l = navigator.language) => [f.toLocaleUpperCase(l), ...r].join(''),
    reset: function () {
        this.s.playCount = this.objectMap(this.s.index, () => 3)
        for (const s of Object.keys(this.s.playCount)) this.updateMove(s, true)

        this.s.elements.roundCount.innerText = this.s.round = 1

				this.updateSuggestion()

        this.s.elements.instructions.classList.remove('hide')
        this.s.elements.restartSection.classList.add('hide')
    },
    updateMove: function (s) {
        this.s.elements.kemdi[s].getElementsByTagName('img')[0].style.filter = `grayscale(${100 - Math.round(100 * this.s.playCount[s] / 3)}%)`
        this.s.elements.kemdi[s].getElementsByClassName('remaining')[0].innerText = this.s.playCount[s]
    },
    getMaxProperty: function (obj, prop) {
        const entries = Object.entries(obj)
        const maxEntry = entries.slice(1).reduce((currentMax, currentValue) => currentValue[1][prop] > currentMax[1][prop] ? currentValue : currentMax, entries[0])
        return maxEntry[0]
    },
    updateSuggestion: function () {
        const total = Object.values(this.s.playCount).reduce((t, c) => t + c, 0)
        const chances = this.objectMap(this.s.playCount, v => ({ c: v / total, hide: false }))
        const type = this.getMaxProperty(chances, 'c')
        let reason
        // https://stackoverflow.com/a/35568895
        if (Object.values(chances).every((v, i, a) => v.c === a[0].c)) reason = 'The odds of each pick are EQUAL.'
        else {
            if (chances[type].c === chances[this.s.index[type][0]].c) {
                for (const t of this.s.index[type]) chances[t].hide =...