Two teams try and fill in any horizontal, vertical, or diagonal line on a bingo board by playing maps on osu!
osu.bingo
osu
1<script lang="ts">
2 import { checkWin } from '$lib/bingo-helpers/check_win';
3 import type { Writable } from 'svelte/store';
4
5 export let cardStore: Writable<Bingo.Card | null>;
6 export let cardPadding = 5;
7 export let padding = 5;
8 export let labels = true;
9 export let rounded = true;
10
11 let yMax: number;
12 let xMax: number;
13
14 let winningLine: number[] | null = null;
15
16 const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
17
18 cardStore.subscribe((card) => {
19 if (!card) return;
20
21 if (card.squares) {
22 yMax = Math.max(...card.squares.map((x) => x.y_pos));
23 xMax = Math.max(...card.squares.map((x) => x.x_pos));
24 }
25 const win = checkWin(card);
26 if (win) {
27 winningLine = win.line;
28 }
29 });
30</script>
31
32<div
33 class="grid w-full rounded p-[var(--p2)]"
34 style="
35 --p2: {cardPadding}px;
36 grid-template-columns: repeat({xMax + 1}, {xMax + 1}fr);
37 grid-template-rows: repeat({yMax + 1}, {yMax + 1}fr);
38 aspect-ratio: {xMax + 1} / {yMax + 1}
39 "
40>
41 {#if $cardStore && $cardStore.squares}
42 {#each $cardStore.squares as square, i}
43 <div
44 class="p-[var(--p)]"
45 style="grid-area: {square.y_pos + 1} / {square.x_pos + 1} / {square.y_pos +
46 2} / {square.x_pos + 2}; --p: {padding}px; --r: {rounded ? padding : 0}px"
47 >
48 <div
49 class="flex size-full items-center justify-center rounded-[var(--r)] bg-base-700 font-rounded text-2xl font-black text-white/50 data-[winning=true]:animate-pulse data-[team=BLUE]:bg-blue-600 data-[team=RED]:bg-red-500"
50 data-team={square.claimed_by?.team_name.toUpperCase()}
51 data-winning={winningLine?.includes(i)}
52 >
53 {#if labels}
54 {alphabet.charAt(square.x_pos)}{square.y_pos + 1}
55 {/if}
56 </div>
57 </div>
58 {/each}
59 {/if}
60</div>