SET

SET THE CARD GAME By Anne-Greeth Schot-van Herwijnen

SHAPE

SHAPE FILLING

SHAPE FILLING AMOUNT

SHAPE FILLING COLOR AMOUNT GREEN RED PURPLE

SO WHAT’S A SET?

isSet(cardA, cardB, cardC) { return ( this.validateProps(cardA.shape, cardB.shape, cardC.shape) && this.validateProps(cardA.amount, cardB.amount, cardC.amount) && this.validateProps(cardA.filling, cardB.filling, cardC.filling) && this.validateProps(cardA.color, cardB.color, cardC.color) ); }

validateProps(propCardA, propCardB, propCardC) { return (propCardA === propCardB && propCardB === propCardC) || (propCardA !== propCardB && propCardA !== propCardC && propCardB !== propCardC); }

~% EMBER GENERATE COMPONENT CARD

<button …attributes data-test-card type=”button” {{on “click” (fn this.handleClick @image) }} local-class=”button {{if @selected “selected” “”}} {{if @wrong “wrong”}} {{if @hint “hint”}}”> <img src={{@image}} alt={{@image}} local-class=”img”/> </button>

<button …attributes data-test-card type=”button” {{on “click” (fn this.handleClick @image) }} local-class=”button {{if @selected “selected” “”}} {{if @wrong “wrong”}} {{if @hint “hint”}}”> <img src={{@image}} alt={{@image}} local-class=”img”/> </button> .button.hint { border: 3px dashed #4caf50; } .button.selected { border: 3px solid orange; } .button.wrong { border: 3px solid red; animation: shake … transform: translateX(0, 0, 0); }

<button …attributes data-test-card type=”button” {{on “click” (fn this.handleClick @image) }} local-class=”button {{if @selected “selected” “”}} {{if @wrong “wrong”}} {{if @hint “hint”}}”> <img src={{@image}} alt={{@image}} local-class=”img”/> </button> .button.hint { border: 3px dashed #4caf50; } .button.selected { border: 3px solid orange; } .button.wrong { border: 3px solid red; animation: shake … transform: translateX(0, 0, 0); } @keyframes shake { 10%, 90% { transform: translateX(-1px); } 20%, 80% { transform: translateX(2px); } 30%, 50%, 70% { transform: translateX(-4px); } 40%, 60% { transform: translateX(4px); } }

~% EMBER GENERATE COMPONENT PLAYINGFIELD

<div local-class=”playing-field”> {{#each this.field as |card|}} <Card @image={{card.image}} @selected={{card.selected}} @wrong={{card.wrong}} @hint={{card.hint}} @onSelect={{this.selectCard}}/> {{/each}} </div>

<div local-class=”playing-field”> {{#each this.field as |card|}} <Card @image={{card.image}} @selected={{card.selected}} @wrong={{card.wrong}} @hint={{card.hint}} @onSelect={{this.selectCard}}/> {{/each}} if (this.args.easy) { </div> this.cards = this.getSimpleDeck(); this.field = […this.getCards(9)]; while (!this.hasSet) { this.cards = this.getSimpleDeck(); this.field = […this.getCards(9)]; } } else { this.cards = this.getDeck(); this.field = […this.getCards(12)]; while (!this.hasSet) { this.cards = this.getDeck(); this.field = […this.getCards(12)]; } }

<div local-class=”playing-field”> {{#each this.field as |card|}} <Card @image={{card.image}} @selected={{card.selected}} @wrong={{card.wrong}} @hint={{card.hint}} @onSelect={{this.selectCard}}/> {{/each}} if (this.args.easy) { </div> getRandomCard(cards) { const randomIndex = Math.floor(Math.random() * cards.length); let randomCard = cards[randomIndex]; cards.splice(randomIndex, 1); return { rc: randomCard, cards: cards }; } this.cards = this.getSimpleDeck(); this.field = […this.getCards(9)]; while (!this.hasSet) { this.cards = this.getSimpleDeck(); this.field = […this.getCards(9)]; } } else { this.cards = this.getDeck(); this.field = […this.getCards(12)]; while (!this.hasSet) { this.cards = this.getDeck(); this.field = […this.getCards(12)]; } }

@task *timerTask() { while (true) { yield new Promise((resolve) => setTimeout(resolve, 1000)); this.time = Math.floor((Date.now() - this.startTime) / 1000); } }

@action getHint() { const combinations = this.k_combinations(this.field, 3); let foundSet = combinations.find((comb) => this.isSet(…comb)); foundSet[Math.floor(Math.random() * 3)].hint = true; if (this.hintsActive < 3) { this.hintCounter++; this.hintsActive++; } }

let highscoresString = localStorage.getItem(‘highscores’); this.highscores = JSON.parse(highscoresString)?.sort((a, b) => a > b) localStorage.setItem(‘highscores’, JSON.stringify(this.highscores)); localStorage.clear();

“ember-web-app”: “^5.0.1”

“ember-web-app”: “^5.0.1”

MULTIPLAYER COLOR PICKING

SET-THE-GAME.NETLIFY.APP GITHUB: @MINTHAMIE TWITTER: @AGVANHERWIJNEN INSTAGRAM: @A.G.VANHERWIJNEN NOTIST: NOTI.ST/MINTHAMIE