Skip to content

Instantly share code, notes, and snippets.

@oelna
Created November 14, 2025 15:43
Show Gist options
  • Select an option

  • Save oelna/5e9aa8975226745febff9cc443b7c2c4 to your computer and use it in GitHub Desktop.

Select an option

Save oelna/5e9aa8975226745febff9cc443b7c2c4 to your computer and use it in GitHub Desktop.
First draft at HTML/JS memory game by @l3o_fi
<!doctype html>
<html lang="de" class="home">
<head>
<meta charset="UTF-8">
<title>Stunde 6 Demos</title>
<link rel="stylesheet" href="style.css" />
<script src="script.js" defer></script>
<script src="https://unpkg.com/alpinejs" defer></script>
</head>
<body>
<div class="game" x-data="{ cards: [] }" x-init="cards = newDeck(6)">
<header>A</header>
<nav>B</nav>
<main>
<template x-for="card in cards">
<details class="card" x-bind:data-card-suit="card.suit" @click="check($event, card)" x-data="{ open: null, solved: false }" x-bind:open="open ? '' : null">
<summary class="card-back">Card Back</summary>
<div class="card-front" inert>
<h2 x-text="card.title +' of '+ card.suit"></h2>
</div>
</details>
</template>
</main>
<aside>C</aside>
<footer>D</footer>
</div>
</body>
</html>
const cards = [
['Hearts', 'Ace', 10],
['Hearts', 'King', 10],
['Hearts', 'Queen', 10],
['Hearts', 'Jack', 10],
['Hearts', 'Ten', 10],
['Spades', 'Ace', 10],
['Spades', 'King', 10],
['Spades', 'Queen', 10],
['Spades', 'Jack', 10],
['Spades', 'Ten', 10],
['Clubs', 'Ace', 10],
['Clubs', 'King', 10],
['Clubs', 'Queen', 10],
['Clubs', 'Jack', 10],
['Clubs', 'Ten', 10],
['Diamonds', 'Ace', 10],
['Diamonds', 'King', 10],
['Diamonds', 'Queen', 10],
['Diamonds', 'Jack', 10],
['Diamonds', 'Ten', 10],
];
let previousSuit = '';
let streak = 0;
const maxStreak = 4;
function shuffleArray (array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
}
function newCard (suit, title, val) {
return {
'title': title,
'val': val
}
}
function newDeck (size=10) {
const deck = cards.map((card) => {
return {
title: card[1],
suit: card[0],
val: card[2]
}
});
shuffleArray(deck);
console.log(deck);
return deck;
}
function hideAll () {
document.querySelectorAll('main .card').forEach(function (ele, i) {
ele.removeAttribute('open');
});
}
function check (event, card) {
// console.log(event.target.closest('details'));
if (event.target.closest('details').classList.contains('cleared')) {
console.log('don\'t turn');
event.target.closest('details').setAttribute('open', '')
return false;
}
if (previousSuit.length == 0) {
// first card opened
previousSuit = card.suit;
console.log('first card', card.suit);
} else if (card.suit == previousSuit) {
// suits match
streak += 1;
console.log('match!', card.suit);
// check win condition
if (streak == maxStreak) {
// mark as solved
document.querySelectorAll('main .card[data-card-suit="'+card.suit+'"]').forEach(function (ele, i) {
console.log(ele);
ele.classList.add('cleared');
});
}
} else {
// suits don't match
streak = 0;
previousSuit = card.suit;
hideAll();
console.log('awwwww!', card.suit);
}
// console.log('is open?', ele, card.open);
console.log('streak', streak);
// console.log(this, card, event.target.closest('details'));
}
* {
box-sizing: border-box;
}
html {
font: 150%/1.4 system-ui, sans-serif;
background-color: #ccc;
}
html.home {
}
.game {
background-color: #fff;
width: 80%;
padding: 1.5rem;
margin-block: 2rem 5rem;
margin-inline: auto;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.game > * {
outline: 1px solid red;
min-height: 5rem;
}
.game header {
grid-column-start: span 3;
}
.game nav {
grid-column-start: span 3;
}
.game main {
grid-column-start: span 2;
padding: 0.5rem;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.game main {}
.game aside {
grid-column-start: span 1;
}
.game footer {
grid-column-start: span 3;
}
details.card {
outline: 1px solid green;
width: 200px;
height: 200px;
position: relative;
cursor: pointer;
}
details.card summary.card-back {
background: #ccc;
position: absolute;
z-index: 100;
top: 0;
width: 100%;
height: 100%;
user-select: none;
text-indent: -9000px;
}
details.card .card-front {
outline: 1px solid orange;
position: absolute;
z-index: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
user-select: none;
}
details.card[open] .card-back {
opacity: 0;
}
details.card.cleared .card-front {
background: red;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment