Skip to content

Simple Game

Gold: /
Health:
Reward: Cost:

Code

The following example assumes that you have imported the component and set up the theme.

Simple Game
<wcp-template id="mine-cell">
31 collapsed lines
<template>
<div class="cell" template-repeat="random:index">
<wcp-ui-state>
<wcp-store type="boolean" name="$opened" value="false"></wcp-store>
<wcp-store
type="string"
name="$type"
value='[[ random[index] < 0.2 ? "trap" : random[index] < 0.7 ? "gold" : "empty" ]]'
></wcp-store>
<button
class="cell-button"
bind-attr='aria-label:($opened ? $type : "unknown") + " cell in row " + [[ Math.floor(index / 6) + 1 ]] + " column " + [[ (index % 6 ) + 1 ]]'
bind-attr-toggle="disabled:$opened || $lost"
bind-class="$opened ? $type : ''"
bind-event='click:
$opened(!$opened),
(
$type === "trap"
? $health($health - 1)
: $type === "gold"
? $gold($gold + $reward)
: null
)'
bind-text='$opened ? ($type === "trap" ? "💣" : $type === "gold" ? "🪙" : ".") : "?"'
>
?
</button>
</wcp-ui-state>
</div>
</template>
</wcp-template>
<wcp-ui-state>
<wcp-store type="number" name="$gold" value="0"></wcp-store>
<wcp-store type="number" name="$health" value="5"></wcp-store>
<wcp-store type="number" name="$target" value="25"></wcp-store>
<wcp-store type="number" name="$shovelCost" value="5"></wcp-store>
<wcp-store type="number" name="$reward" value="2"></wcp-store>
<wcp-store derive="$gold >= $target" name="$won"></wcp-store>
<wcp-store derive="$health <= 0" name="$lost"></wcp-store>
<div class="mine-game">
54 collapsed lines
<div class="topbar">
<div>
Gold:
<strong class="gold" bind-text="$gold"></strong>
/
<span class="gold" bind-text="$target"></span>
</div>
<div>
Health:
<strong bind-text="$health"></strong>
</div>
</div>
<div class="shop">
<button
bind-attr-toggle="disabled:$gold < $shovelCost || $lost"
bind-event="click:$gold($gold - $shovelCost), $reward($reward + 1), $shovelCost($shovelCost + 5)"
>
Upgrade Shovel
</button>
<span>
Reward:
<strong class="gold" bind-text="$reward"></strong>
</span>
<span>
Cost:
<strong class="gold" bind-text="$shovelCost"></strong>
</span>
</div>
<div class="board">
<wcp-template prop-random:js="Array(6 * 6).fill().map(Math.random)" use="mine-cell"></wcp-template>
</div>
<div class="status">
<div class="win" style="display: none" bind-show="$won">You reached the gold target.</div>
<div class="lose" style="display: none" bind-show="$lost && !$won">You ran out of health.</div>
<br />
<button
class="restart-button"
bind-event="click:
$gold(0),
$health(5),
$target(25),
$shovelCost(5),
$reward(2)
"
>
Restart
</button>
</div>
</div>
</wcp-ui-state>
<script>
17 collapsed lines
// @ts-check
document.addEventListener("DOMContentLoaded", () => {
/** @type {HTMLButtonElement | null} */
const restartButton = document.querySelector(".restart-button");
/** @type {HTMLDivElement | null} */
const board = document.querySelector(".board");
restartButton?.addEventListener("click", () => {
const newTemplate = document.createElement("wcp-template");
newTemplate.setAttribute("prop-random:js", "Array(6 * 6).fill().map(Math.random)");
newTemplate.setAttribute("use", "mine-cell");
board?.replaceChildren(newTemplate);
});
});
</script>
<style>
96 collapsed lines
.mine-game {
display: flex;
flex-direction: column;
gap: 1rem;
max-inline-size: 32rem;
margin: auto;
color: var(--sb-color-text);
}
.gold {
color: light-dark(#ba9e00, gold);
}
.topbar,
.shop {
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: center;
}
.board {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 0.5rem;
}
.cell {
display: flex;
}
.cell-button {
flex: 1;
aspect-ratio: 1;
font-size: var(--sb-text-lg);
font-weight: 700;
color: var(--sb-color-text);
cursor: pointer;
background: var(--sb-color-gray-6);
border: 1px solid var(--sb-color-gray-4);
border-radius: 8px;
&:disabled {
cursor: default;
}
&:hover:not(:disabled) {
border-color: var(--sb-color-accent);
}
&.gold {
background: var(--sb-color-accent-low);
border-color: var(--sb-color-accent);
}
&.trap {
background: var(--sb-caution-background);
border-color: var(--sb-caution-border);
}
&.empty {
background: var(--sb-color-gray-7);
}
}
.shop button,
.restart-button {
padding: 0.6rem 1rem;
color: #fff;
cursor: pointer;
background: var(--sb-color-accent);
border: 0;
border-radius: 8px;
&:disabled {
filter: grayscale();
}
}
.win,
.lose {
padding: 0.75rem;
border-radius: 8px;
}
.win {
color: var(--sb-tip-text);
background: var(--sb-tip-background);
border: 1px solid var(--sb-tip-border);
}
.lose {
color: var(--sb-caution-text);
background: var(--sb-caution-background);
border: 1px solid var(--sb-caution-border);
}
</style>